Get all matches for a certain pattern using RegEx - regex

I am not really a RegEx expert and hence asking a simple question.
I have a few parameters that I need to use which are in a particular pattern
For example
$$DATA_START_TIME
$$DATA_END_TIME
$$MIN_POID_ID_DLAY
$$MAX_POID_ID_DLAY
$$MIN_POID_ID_RELTM
$$MAX_POID_ID_RELTM
And these will be replaced at runtime in a string with their values (a SQL statement).
For example I have a simple query
select * from asdf where asdf.starttime = $$DATA_START_TIME and asdf.endtime = $$DATA_END_TIME
Now when I try to use the RegEx pattern
\$\$[^\W+]\w+$
I do not get all the matches(I get only a the last match).
I am trying to test my usage here https://regex101.com/r/xR9dG0/2
If someone could correct my mistake, I would really appreciate it.
Thanks!

This will do the job:
\$\$\w+/g
See Demo
Just Some clarifications why your regex is doing what is doing:
\$\$[^\W+]\w+$
Unescaped $ char means end of string, so, your pattern is matching something that must be on the end of the string, that's why its getting only the last match.
This group [^\W+] doesn't really makes sense, groups starting with [^..] means negate the chars inside here, and \W is the negation of words, and + inside the group means literally the char +, so you are saying match everything that is Not a Not word and that is not a + sign, i guess that was not what you wanted.
To match the next word just \w+ will do it. And the global modifier /g ensures that you will not stop on the first match.

This should work - Based on what you said you wanted to match this should work . Also it won't match $$lower_case_strings if that's what you wanted. If not, add the "i" flag also.
\${2}[A-Z_]+/g

Related

How to use regex to select whole string in one match except the forward slash /

I need some help with regex with this test string:
Kershing_User ID/Electronic Delivery_6ZZ138429_ 3142-999999__1
I want one match to select everything except the forward slash, so this would be acceptable:
Kershing_User IDElectronic Delivery_6ZZ138429_ 3142-999999__1
Even better would be to return this with a substitution of a _.
Kershing_User ID_Electronic Delivery_6ZZ138429_ 3142-999999__1
I know how to do lookarounds and can individually match the part before and after the /, but not all in one match. Anything else I have tried has come up with two separate matches. I am using this with an application called Laserfiche, so as far as I know there is not the ability to do find & replace or to extract a group, just doing it with one match. My regrets if I don't have the terminology correct. I am not even sure if this is possible. I tried for a while and come up with these below, but can't get it in one match.
This does the before: .*(?=\/)
This does the after: (?<=\/).*
Even better would be to return this with a substitution of a _.
import re
a = "Kershing_User ID/Electronic Delivery_6ZZ138429_ 3142-999999__1"
print(re.sub('\/', '_', a))
This will replace / with _. Read more on this here

Case analysis with REGEX

I have some data like
small_animal/Mouse
BigAnimal:Elephant
Not an animal.
What I want to get is:
Mouse
Elephant
Not an animal.
Thus, I need a regular expression that searches for / or : as follows: If one of these is found, take the text behind that character. If neither / nor : exists, take the whole string.
I tried a lot. For example this will work for mouse and elephant, but not for the third line:
(?<=:)[^:]*|(?<=/)[^/]*
And this will always give the full string ...
(?<=:)[^:]*|(?<=/)[^/]*|^.*$
My head is burning^^ Maybe, somebody can help? :) Thanks a lot!
EDIT:
#The fourth bird offered a nice solution for single characters. But what if I want to search for strings like
animal::Dog
Another123Cat
Not an animal.
How can I split on :: or 123?
You might use
^(?:[^:/]*[:/])?\K.+
^ Start of string
(?:[^:/]*[:/])? Optionally match any char except : or / till matching either : or /
\K Forget what is matched so far
.+ Match 1+ times any char
regex demo
If you don't want to cross a newline, you can extend the character class with [^:/\r\n]*
Another option could be using an alternation
^[^:/]*[:/]\K.+|.+
Regex demo
Or perhaps making use of a SKIP FAIL approach by matching what you want to omit
^[^:/]*[:/](*SKIP)(*F)|.+
Regex demo
If you want to use multiple characters, you might also use
^(?:(?:(?!123|::|[:/]).)*+(?:123|::|[:/]))?\K.+
Regex demo

regex to match all subfolders of a URL, except a few special ones

OK, I'm writing a regex that I want to match on a certain url path, and all subfolders underneath it, but with a few excluded. for context, this is for use inside verizon edgecast, which is a CDN caching system. it supports regex, but unfortunately i don't know the 'flavor' of regex it supports and the documentation isn't clear about that either. Seems to support all the core regex features though, and that should be all i need. unfortunately reading the documentation requires an account, but you can get the general idea of edgecast here: https://www.verizondigitalmedia.com/platform/edgecast-cdn/
so, here is some sample data:
help
help/good
help/better
help/great
help/bad
help/bad/worse
and here is the regex I am using right now:
(^help$|help\/[^bad].*)
link: https://regex101.com/r/CBWUDE/1
broken down:
( - start capture group
^ - start of string
help - 1st thing that should match
$ - end of string
| - or
help - another thing that should match
\/ - escaped / so i can match help/
[^bad] - match any single character that isn't b, a, or d
. - any character
* - any number of times
) - end capture group
I would like the first 4 to match, but not the last 2, 'bad' or 'bad/worse' should not be matches, and help/anythingelse should be a match
this regex is working for me, except that help/better is not a match. the reason it's not a match, i'm pretty sure, is because better, contains a character that appears inside 'bad'. if i change 'bettter' to 'getter' then it becomes a match, because it no longer has a b in it.
so what i really want is my 'bad' to only match the whole word bad, and not match any thing with b, a, or d in it. I tried using word boundary to do this, but isn't giving me the results i need, but perhaps i just have the syntax wrong, this is what i tried:
(^help$|help\/[^\bbad\b].*)
but does not seem to work, the 'bad' urls are no longer excluded, and help/better is still not matching with that. I think it's because / is not a word boundary. I'm positive my problem with the original regex is with the part:
[^bad] - match any single character that isn't b, a, or d
my question is, how can i turn [^bad] into something that matches anything that doesn't contain the full string 'bad'?
You're going to want to use negative look ahead (?!bad) instead of negating specific letters [^bad]
I think (^help$|help\/(?!bad).*) is what you're looking for
Edit: if you mean anything with the word bad at all, not just help/bad you can make it (?!.*bad.*) This would prevent you from matching help/matbadtom for example. Full regex: (^help$|help\/(?!.*bad.*).*)

Interesting easy looking Regex

I am re-phrasing my question to clear confusions!
I want to match if a string has certain letters for this I use the character class:
[ACD]
and it works perfectly!
but I want to match if the string has those letter(s) 2 or more times either repeated or 2 separate letters
For example:
[AKL] should match:
ABCVL
AAGHF
KKUI
AKL
But the above should not match the following:
ABCD
KHID
LOVE
because those are there but only once!
that's why I was trying to use:
[ACD]{2,}
But it's not working, probably it's not the right Regex.. can somebody a Regex guru can help me solve this puzzle?
Thanks
PS: I will use it on MYSQL - a differnt approach can also welcome! but I like to use regex for smarter and shorter query!
To ensure that a string contains at least two occurencies in a set of letters (lets say A K L as in your example), you can write something like this:
[AKL].*[AKL]
Since the MySQL regex engine is a DFA, there is no need to use a negated character class like [^AKL] in place of the dot to avoid backtracking, or a lazy quantifier that is not supported at all.
example:
SELECT 'KKUI' REGEXP '[AKL].*[AKL]';
will return 1
You can follow this link that speaks on the particular subject of the LIKE and the REGEXP features in MySQL.
If I understood you correctly, this is quite simple:
[A-Z].*?[A-Z]
This looks for your something in your set, [A-Z], and then lazily matches characters until it (potentially) comes across the set, [A-Z], again.
As #Enigmadan pointed out, a lazy match is not necessary here: [A-Z].*[A-Z]
The expression you are using searches for characters between 2 and unlimited times with these characters ACDFGHIJKMNOPQRSTUVWXZ.
However, your RegEx expression is excluding Y (UVWXZ])) therefore Z cannot be found since it is not surrounded by another character in your expression and the same principle applies to B ([ACD) also excluded in you RegEx expression. For example Z and A would match in an expression like ZABCDEFGHIJKLMNOPQRSTUVWXYZA
If those were not excluded on purpose probably better can be to use ranges like [A-Z]
If you want 2 or more of a match on [AKL], then you may use just [AKL] and may have match >= 2.
I am not good at SQL regex, but may be something like this?
check (dbo.RegexMatch( ['ABCVL'], '[AKL]' ) >= 2)
To put it in simple English, use [AKL] as your regex, and check the match on the string to be greater than 2. Here's how I would do in Java:
private boolean search2orMore(String string) {
Matcher matcher = Pattern.compile("[ACD]").matcher(string);
int counter = 0;
while (matcher.find())
{
counter++;
}
return (counter >= 2);
}
You can't use [ACD]{2,} because it always wants to match 2 or more of each characters and will fail if you have 2 or more matching single characters.
your question is not very clear, but here is my trial pattern
\b(\S*[AKL]\S*[AKL]\S*)\b
Demo
pretty sure this should work in any case
(?<l>[^AKL\n]*[AKL]+[^AKL\n]*[AKL]+[^AKL\n]*)[\n\r]
replace AKL for letters you need can be done very easily dynamicly tell me if you need it
Is this what you are looking for?
".*(.*[AKL].*){2,}.*" (without quotes)
It matches if there are at least two occurences of your charactes sorrounded by anything.
It is .NET regex, but should be same for anything else
Edit
Overall, MySQL regular expression support is pretty weak.
If you only need to match your capture group a minimum of two times, then you can simply use:
select * from ... where ... regexp('([ACD].*){2,}') #could be `2,` or just `2`
If you need to match your capture group more than two times, then just change the number:
select * from ... where ... regexp('([ACD].*){3}')
#This number should match the number of matches you need
If you needed a minimum of 7 matches and you were using your previous capture group [ACDF-KM-XZ]
e.g.
select * from ... where ... regexp('([ACDF-KM-XZ].*){7,}')
Response before edit:
Your regex is trying to find at least two characters from the set[ACDFGHIJKMNOPQRSTUVWXZ].
([ACDFGHIJKMNOPQRSTUVWXZ]){2,}
The reason A and Z are not being matched in your example string (ABCDEFGHIJKLMNOPQRSTUVWXYZ) is because you are looking for two or more characters that are together that match your set. A is a single character followed by a character that does not match your set. Thus, A is not matched.
Similarly, Z is a single character preceded by a character that does not match your set. Thus, Z is not matched.
The bolded characters below do not match your set
ABCDEFGHIJKLMNOPQRSTUVWXYZ
If you were to do a global search in the string, only the italicized characters would be matched:
ABCDEFGHIJKLMNOPQRSTUVWXYZ

how to group in regex matching correctly?

consider following scenario
input string = "WIPR.NS"
i have to replace this with "WIPR2.NS"
i am using following logic.
match pattern = "(.*)\.NS$" \\ any string that ends with .NS
replace pattern = "$12.NS"
In above case, since there is no group with index 12, i get result $12.NS
But what i want is "WIPR2.NS".
If i don't have digit 2 to replace, it works in all other cases but not working for 2.
How to resolve this case?
Thanks in advance,
Alok
Usually depends entirely on your regex engine (I'm not familiar with those that use $1 to represent a capture group, I'm more used to \1 but you'd have the same problem with that).
Some will provide a delimiter that you can use, like:
replace pattern = "${1}2.NS"
which clearly indicates that you want capture group 1 followed by the literal 2.NS.
In fact, by looking at this page, it appears that's exactly the way to do it (assuming .NET):
To replace with the first backreference immediately followed by the digit 9, use ${1}9. If you type $19, and there are less than 19 backreferences, the $19 will be interpreted as literal text, and appear in the result string as such.
Also keep in mind that Jay provides an excellent answer for this specific use case that doesn't require capture groups at all (by just replacing .NS with 2.NS).
You may want to look into that as a possibility - I'll leave this answer here since:
it's the accepted answer; and
it probably better for the more complex cases, like changing X([A-Z])4([A-Z]) with X${1}5${2}, where you have variable text on either side of the bit you wish to modify.
You don't need to do anything with what precedes the .NS, since only what is being matched is subject to replacement.
match pattern = "\.NS$" (any string that ends with .NS -- don't forget to escape the .)
replace pattern = "2.NS"
You can further refine this with lookaround zero-width assertions, but that depends on your regex engine, and you have not specified the environment/programming language in which you are working.