I am trying to match a param string but exclude any matches when a substring is present.
From my limited regex knowledge this should work to exlude any string containing "porcupine", but it's not. What am I doing wrong?
(\/animal\?.*(?!porcupine).*color=white)
Expected Outcome
| string | matches? |
| ----------------------------------------------- | -------- |
| /animal?nose=wrinkly&type=porcupine&color=white | false |
| /animal?nose=wrinkly&type=puppy&color=white | true |
Actual Outcome
| string | matches? |
| ----------------------------------------------- | -------- |
| /animal?nose=wrinkly&type=porcupine&color=white | true |
| /animal?nose=wrinkly&type=puppy&color=white | true |
Use a Tempered Greedy Token:
/animal\?(?:(?!porcupine).)*color=white
Demo & explanation
The .* searches anything for any number of times, greedily. So you could replace it with a literal search:
(\/animal\?nose=wrinkly\&type=(?!porcupine).*color=white)
See example here: https://regex101.com/r/HJiM2N/1
This may seem overly verbose but it is actually relatively efficient in the number of steps:
(?!\/animal.*?porcupine.*?color)\/animal\?.*color=white
See Regex Demo
If the input string consists of only one and only one occurrence of what you are trying to match and nothing else, then just use the following to ensure that porcupine does not occur anywhere in the input string:
(?!.*porcupine)\/animal\?.*color=white
The code:
import re
tests = [
'/animal?nose=wrinkly&type=porcupine&color=white',
'/animal?nose=wrinkly&type=puppy&color=white'
]
rex = r'(?!\/animal.*?porcupine.*?color)\/animal\?.*color=white'
for test in tests:
m = re.search(rex, test)
print(test, 'True' if m else 'False')
Prints:
/animal?nose=wrinkly&type=porcupine&color=white False
/animal?nose=wrinkly&type=puppy&color=white True
Related
I am trying to write a RegEx on the following text:
CpuUtilization\[GqIF:CA-TORONTO-1-AD-1 | FAULT-DOMAIN-3 | ocid1.image.oc1.ca-toronto-1.aaaaaaaaq4cxrudcxy5seck2cweks2zglo2tfieag6svtvqssa2zmjha | Default | ca-toronto-1 | oke-ccf3jglvbia-nc7pit2gv2a-sa65utwc32a-2 | ocid1.instance.oc1.ca-toronto-1.an2g6ljrwe6j4fqcgrlo7dmzkrtbcgr3jy35gie3qh3w65ctfh3hsd6da | VM.Standard.E2.2\]
I need to extract oke-ccf3jglvbia-nc7pit2gv2a-sa65utwc32a-2 from the statement. The text above can change depending, so looking for a generic RegEx.
I tried using: (\[^\\|\]+)\\|.+ which extract the first occurrence before |
Why use RegEx?
const s = 'CpuUtilization\[GqIF:CA-TORONTO-1-AD-1 | FAULT-DOMAIN-3 | ocid1.image.oc1.ca-toronto-1.aaaaaaaaq4cxrudcxy5seck2cweks2zglo2tfieag6svtvqssa2zmjha | Default | ca-toronto-1 | oke-ccf3jglvbia-nc7pit2gv2a-sa65utwc32a-2 | ocid1.instance.oc1.ca-toronto-1.an2g6ljrwe6j4fqcgrlo7dmzkrtbcgr3jy35gie3qh3w65ctfh3hsd6da | VM.Standard.E2.2\]'
console.log(s.split(" | ")[5])
A regex solution can be
^(?:[^|]+ \| ){5}([^ ]+).*$
^ start of the string
(?:[^|]+ \| ){5} any character but \ followed by |, 5 times. (The ?: makes this a non capturing group).
([^ ]+) your string as the first group
.*$ any character to end of line
To get your string out of this, subtitute it with $1 or \1.
Test it on regex101. There you can test different programming languages/regex processors.
Remark:
Like the answer of Kazi this works in this case, maybe not in others.
There are no more examples in you question.
This answer is in function nearly the same.
I am stuck trying to figure out how to get a RegEx text search to work with a dollar sign. Let's say I have two strings:
TestPerson One | 123456789 | ($100.00) | $0 | 03/27/2018 | Open
TestPerson Two | 987654321 | ($250.00) | ($25) | 03/27/2018 | Open
Using jQuery, I am creating the RegEx. If I was to search for TestPerson, the RegEx would look like this:
/^(?=.*\bTestPerson).*$/i
This would return both strings, as they both contain TestPerson. If I try and search for $, I get zero results even though both strings contian a $. I know the dollar sign is a special character in RegEx, but escaping it does not work either.
How can I format my RegEx to where searching for $ will return both results?
Thanks!
I think this seems multiline modifier on-off problem. I guess you turned off the multiline modifier and implemented the regex so the unexpected output results. Demo
If you turned on the multiline modifier, you could get the output you want. Demo
To check whether or not a string contains a substring, you don't regex: JavaScript has the string method includes(). This method searches a string for a given value and returns true if it exists in the string and false otherwise.
var a = [
'TestPerson One | 123456789 | ($100.00) | $0 | 03/27/2018 | Open',
'TestPerson Two | 987654321 | ($250.00) | ($25) | 03/27/2018 | Open'
]
a.forEach(function(s) {
console.log(s.includes('TestPerson') && s.includes('$'))
})
I am trying to match, the following cases:
1. Get either between or if only one x exists the end
Example:
| Matches/Cases | Result |
|-------------------|--------|
| 200 x 90 x 14 | 90 |
| 90x200 | 200 |
| 200 x 90x20 | 90 |
| 60,4 x46,5 x 42,6 | 46,5 |
| 90x190,9 | 190,9 |
2. Get if two x exist the final one, and if only one exist no result
Examples:
| Matches/Cases | Result |
|-------------------|--------|
| 200 x 90 x 14 | 14 |
| 90x200 | - |
| 200 x 90x20 | 20 |
| 60,4 x46,5 x 42,6 | 42,6 |
| 90x190,9 | - |
I stuck at getting one specific case! I tried to match with the following regex x\s?((\d+(?:,\d+)?))\s?, but I still get only the last part of the cases like for 90x200 I get 200, but for 200 x 90 x 14 I get 90 x 14.
Any suggestions of two regex that works for case 1 or case 2?
I appreciate your replies!
I tried to match with the following regex x\s?((\d+(?:,\d+)?))\s?, but
I still get only the last part of the cases.
Actually by your own RegEx you are going to capture all digits or floats followed by a x. So it's not only last part but all similar occurrences.
Solution (main regex):
(?: *(\d+(?:,\d+)?) *(?:x|$))
If you want it for case #1 then append quantifier {2}
(?: *(\d+(?:,\d+)?) *(?:x|$)){2}
Live demo
If you want it for case #2 append quantifier {3}
(?: *(\d+(?:,\d+)?) *(?:x|$)){3}
Live demo
m modifier should be set in both cases
Just turning the comments into an answer.
For the first case, you could use:
[\d,]+\h*x\h*([\d,]+)(?:\h*x*[\d,]+)?
See a demo on regex101.com.
And the second:
[\d,]+\h*x\h*[\d,]+\h*x\h*([\d,]+)
Another demo on regex101.com.
Hint: Replace \h with either [ ]* or \s* if it is not supported.
I have a string $s1 = "a_b"; and I want to match this string but only capture the letters. I tried to use a lookahead:
if($s1 =~ /([a-z])(?=_)([a-z])/){print "Captured: $1, $2\n";}
but this does not seem to match my string. I have solved the original problem by using a (?:_)instead, but I am curious to why my original attempt did not work? To my understanding a lookahead matches but do not capture, so what did I do wrong?
A lookahead looks for next immediate positions and if a true-assertion takes place it backtracks to previous match - right after a - to continue matching. Your regex would work only if you bring a _ next to the positive lookahead ([a-z])(?=_)_([a-z])
You even don't need (non-)capturing groups in substitution:
if ($s1 =~ /([a-z])_([a-z])/) { print "Captured: $1, $2\n"; }
Edit
In reply to #Borodin's comment
I think that moving backwards is the same as a backtrack which is more recognizable by debugging the whole thing (Perl debug mode):
Matching REx "a(?=_)_b" against "a_b"
.
.
.
0 <> <a_b> | 0| 1:EXACT <a>(3)
1 <a> <_b> | 0| 3:IFMATCH[0](9)
1 <a> <_b> | 1| 5:EXACT <_>(7)
2 <a_> <b> | 1| 7:SUCCEED(0)
| 1| subpattern success...
1 <a> <_b> | 0| 9:EXACT <_b>(11)
3 <a_b> <> | 0| 11:END(0)
Match successful!
As above debug output shows at forth line of results (when 3rd step took place) engine consumes characters a_ (while being in a lookahead assertion) and then we see a backtrack happens after successful assertion of positive lookahead, engine skips whole sub-pattern in a reverse manner and starts at the position right after a.
At line #5, engine has consumed one character only: a. Regex101 debugger:
How I interpret this backtrack is more clear in this illustration (Thanks to #JDB, I borrowed his style of representation)
a(?=_)_b
*
|\
| \
| : a (match)
| * (?=_)
| |↖
| | ↖
| |↘ ↖
| | ↘ ↖
| | ↘ ↖
| | : _ (match)
| | ^ SUBPATTERN SUCCESS (OP_ASSERT :=> MATCH_MATCH)
| * _b
| |\
| | \
| | : _ (match)
| | : b (match)
| | /
| |/
| /
|/
MATCHED
By this I mean if lookahead assertion succeeds - since extraction of parts of input string is happened - it goes back upward (back to previous match offset - (eptr (pointer into the subject) is not changed but offset is) and while resetting consumed chars it tries to continue matching from there and I call it a backtrack. Below is a visual representation of steps taken by engine with use of Regexp::Debugger
So I see it a backtrack or a kind of, however if I'm wrong with all these said, then I'd appreciate any reclaims with open arms.
In the Robot Framework library called String, there are several keywords that allow us to use a regexp to manipulate a string, but these manipulations don't seem to include selecting a substring from a string.
To clarify, what I intend is to have a price, i.e. € 1234,00 from which I would like to select only the 4 primary digits, meaning I am left with 1234 (which I will convert to an int for use in validation calculations). I have a regexp which will allow me to do that, which is as follows:
(\d+)[\.\,]
If I use Remove String Using Regexp with this regexp I will be left with exactly what I tried to remove. If I use Get Lines Matching Regexp, I will get the entire line rather than just the result I wanted, and if I use Get Regexp Matches I will get the right result except it will be in a list, which I will then have to manipulate again so that doesn't seem optimal.
Did I simply miss the keyword that will allow me to do this or am I forced to write my own custom keyword that will let me do this? I am slightly amazed that this functionality doesn't seem to be available, as this is the first use case I would think of when I think of using a regexp with a string...
You can use the Evaluate keyword to run some python code.
For example:
| Using 'Evaluate' to find a pattern in a string
| | ${string}= | set variable | € 1234,00
| | ${result}= | evaluate | re.search(r'\\d+', '''${string}''').group(0) | re
| | should be equal as strings | ${result} | 1234
Starting with robot framework 2.9 there is a keyword named Get regexp matches, which returns a list of all matches.
For example:
| Using 'Get regexp matches' to find a pattern in a string
| | ${string}= | set variable | € 1234,00
| | ${matches}= | get regexp matches | ${string} | \\d+
| | should be equal as strings | ${matches[0]} | 1234