How to escape regular expression characters from variable in JMeter? - regex

Problem is simple. I have regular expression used to extract some data from response. It looks like that:
<input type="hidden" +name="reportpreset_id" +value="(\w+)" *>${reportPresetName}</td>
Problem is that variable ${reportPresetName} may contain characters used by regular expression like parenthesis or dots.
I've tried to surround this variable with \Q and \E (based on that) but apparently these markers don't work (apparently Java supports this markers so I'm confused).
When I'm adding that markers even then this expression fails for any content of ${reportPresetName} variable (even for cases when it was working without those markers).
I've checked list of functions in JMeter, but I didn't found anything useful.
Does anyone know how to escape regular expression characters in JMeter?
update:
When I'm using this \Q and \E with assertion it fails. When I'm doing a copy of regular expression from assertion log in "View Results Tree" and testing it on recorded response data it works! So it looks like some kind bug in JMeter.

Jmeter uses jakarta ORO as its regexp engine in Regexp Extractor and Regexp Tester:
http://jmeter.apache.org/usermanual/regular_expressions.html
But it uses Java Regexp Engine for search in HTML/Text Viewer.
Read:
http://jmeter.apache.org/usermanual/regular_expressions.html $20.4
Please note that ORO does not support the \Q and \E meta-characters.
[In other RE engines, these can be used to quote a portion of an RE so that the
meta-characters stand for themselves.]
A solution for you would be to add a JSR223 post processor using Groovy after regexp that extracts the var and escapes regexp chars using:
org.apache.oro.text.regex.Perl5Compiler.quotemeta(String valueToEscape)
As of upcoming version 2.9, a new function has been created to do so:
__escapeOroRegexpChars(String to escape, Variable Name)

\Q and \E work in Java, see Pattern.
In Java, we use to double the backslash characters, though, so you might need to use (\\w+) and, of course, \\Q and \\E.
I am not sure in your case, as I don't understand your context, actually (never used JMeter so far).

In case JMeter does not support \\Q and \\E (which I don't know if does...), you can write your own function/procedure, where you will split string into characters and replace each character with escaped sequence as follows:
if the character is \, then replace it with \\\\
otherwise add before the character a prefix \\
This is not the optimal method, but for sure it will work as needed.
For example for input
This is-a\string 12&$34|!`^5
you will get
\\T\\h\\i\\s\\ \\i\\s\\-\\a\\\\s\\t\\r\\i\\n\\g\\ \\1\\2\\&\\$\\3\\4\\|\\!\\`\\^\\5

Related

Regex expression format is different in AEM dispatcher

When we create the regex which has a forward slash, then we need to put a backslash before forward-slash since the forward slash is the unescaped delimiter. For example, if I want my regex to match /content/att, then I need to put regex like this
/content\/att. And this works too.
But when we add the dispatcher rule in AEM to allow a url path, the backslash is not needed for the unescaped delimiter. I would appreciate is someone can help me understand this, I mean why we need the backslash when we write the regex, but not when using the same regex in the url path of the dispatcher rule.
In dispatcher, look at the url path – there is no backslash before /att
/type "allow"
/url "/content/att"
/extension '(gif)'
}
I am not familiar with the AEM Dispatcher, but here is the generic answer to your regular expression question:
That is because "/content/att" is the string representation of the regex. The actual regex of that is "/\/content\/att/". Notice that the initial slash in the string is also escaped.
Here is an example: These two JavaScript regular expressions are identical:
let regex1 = /^\/content\/att/;
let regex2 = new RegExp( "^/content/att" );
Short answer: because these are two different types of regex representations.
Long answer:
Historically, regexes have first appeared in text edtors like QED and ed. There, regexes were used for string substitutions (search and replace). The tools needed some way to distinguish the search regex from the replacement string, which is why we got the delimiter. A command to replace some text in ed, for example, would be s«DELIMITER»search-regex«DELIMITER»substitution-string«DELIMITER»flags.
Most single-char delimiters would work but / was often chosen. Of course, it was possible to use the delimiter as part of the regex or the substitution, in which case it would have to be escaped using backslash.
Some programming languages have codified / as the de-facto standard delimiter for regex literals. JavaScript is an example for this.
Now, usages that have no need for a regex to be separated from the substitution (or allow for regex flags) don’t use delimiters at all. Such is the case in Java, where there are no regex literals, regexes are always created from a string using the Pattern class. Which is why, in AEM you don’t need to escape the /.
You didn’t show us your apache dispatcher config file so I’m not sure where you’re escaping the slash there. I know that apache’s mod_rewrite also doesn’t use delimited regexes.

The regular expression used in JavaScript does not work in Java

replace(/[.?+^$[\]\\(){}|-]/g, '\\$&');
But it doesn't work in Java.
So I changed the code as follows.
replace(/[.?+^$[\\]\\\\(){}|-]/g, '\\\\$&');
It doesn't work when I change it. Please help me :(
In Java, replace does not take a regex in the constructor, for that you need replaceFirst.
But as you are using the /g flag in Javascript for all replacements, you can use replaceAll.
In Javascript, this part $& in the replacement points to the full match.
So you want to replace the full match (which is one of these characters [.?+^$[\]\\(){}|-]) prepended by a \
In Java you can use $0 instead to refer to the full match.
You can also escape the opening square bracket in the character class \\[
For example
System.out.println("{test?test^}".replaceAll("[.?+^$\\[\\]\\\\()\\{}|-]", "\\\\$0"));
See a Java demo
Output
\{test\?test\^\}
The same output in Javascript
console.log("{test?test^}".replace(/[.?+^$[\]\\(){}|-]/g, '\\$&'));

RegEx Lookarounds - Using own escape sequence

I'm currently writing a little flatfile database for a project and in that context need to escape list item delimiters.
I decided to use ; as the delimiter and /; as my escaped version of that.
Since I already used RegEx lookarounds in the past, I was sure the following expression I use to split would do the job.
(?<!/);
My expression should match the ; in
abc;def
but should not match the ; in
abc/;def
I used RegExPal and the expression doesn't fit any of my examples.
Isn't this the correct structure of a regular expression to achieve my goal?
(?<!ForbiddenPreceedingExpression)CharacterFollowing
Any hints on where to find my problem?
There is nothing wrong with the regex.
The problem is that Regexpal is a javascript regular expression tester. Java script does not support look behinds.
Take a look at
pcre(php) Demo
where as this one won't
Javascript Demo

Regex doesn't match. Online generator does

I've want to check with a regex this kind of string:
2020_2021_01_01
I've putted it in a variable, say $session
so i do:
if [[ "$session" =~ \d{4}[_]\d{4}[_]\d{2}[_]\d{2} ]]; then
stuff
fi
you see...it doesn't work... but I don't know why....
any help?
THANKS!
The bash manual rather tersely explains that when the =~ operator "is used, the string to the right of the operator is considered an extended regular expression and matched accordingly (as in regex(3))".
Here, regex(3) is a reference to man 3 regex, which might explain what an "extended regular expression" is. A longer description would be "Posix standard extended regular expressions", and you can find the documentation for those in the Posix document. If you're using an online regular expression tester, make sure you select "Posix regular expressions".
In short, they don't include Perlisms like \d. You can write [[:digit:]] or (if you are using the C locale) [0-9].
So your regex could have been written:
([[:digit:]]{4}_){2}[[:digit:]]{2}_[[:digit:]]{2}
(there is no need to quote _). However, be aware that the =~ operator looks for a substring which matches the pattern, rather than testing whether the left-hand operator precisely matches the pattern. So you quite possibly actually wanted an anchored match:
^([[:digit:]]{4}_){2}[[:digit:]]{2}_[[:digit:]]{2}$
The backslash character is an escape character in bash shell. In your example, I think that's making the the regular expression read like this:
d{4}[_]d{4}[_]d{2}[_]d{2}
You could confirm this by testing, setting $session to dddd_dddd_dd_dd
To workaround this, to preserve the backslash character in the regular expression, you'll need to "escape" it. In your case, preceding each backslash with an "extra" backslash may do the trick. The shell will see the two backslashes, and leave the second one, as part of the string.
if [[ "$session" =~ \\d{4}[_]\\d{4}[_]\\d{2}[_]\\d{2} ]]; then
I'm not sure if there are other characters that are going to need to be escaped. This calls for a real short script, one that you can change and run, to figure out what's working and whats not. Can you match the start of the string, a single digit character, etc.
(The whole escaping thing gets funkier... inside double quotes, inside single quotes, ...)
There was a website I used to use, put in the string I wanted, and it would give me back what it needed to look like in the shell script, I don't have a link to that anymore. There's probably a regular expression tester that let's you test "bash" regular expressions.

regex implementation to replace group with its lowercase version

Is there any implementation of regex that allow to replace group in regex with lowercase version of it?
If your regex version supports it, you can use \L, like so in a POSIX shell:
sed -r 's/(^.*)/\L\1/'
In Perl, you can do:
$string =~ s/(some_regex)/lc($1)/ge;
The /e option causes the replacement expression to be interpreted as Perl code to be evaluated, whose return value is used as the final replacement value. lc($x) returns the lowercased version of $x. (Not sure but I assume lc() will handle international characters correctly in recent Perl versions.)
/g means match globally. Omit the g if you only want a single replacement.
If you're using an editor like SublimeText or TextMate1, there's a good chance you may use
\L$1
as your replacement, where $1 refers to something from the regular expression that you put parentheses around. For example2, here's something I used to downcase field names in some SQL, getting everything to the right of the 'as' at the end of any given line. First the "find" regular expression:
(as|AS) ([A-Za-z_]+)\s*,$
and then the replacement expression:
$1 '\L$2',
If you use Vim (or presumably gvim), then you'll want to use \L\1 instead of \L$1, but there's another wrinkle that you'll need to be aware of: Vim reverses the syntax between literal parenthesis characters and escaped parenthesis characters. So to designate a part of the regular expression to be included in the replacement ("captured"), you'll use \( at the beginning and \) at the end. Think of \ as—instead of escaping a special character to make it a literal—marking the beginning of a special character (as with \s, \w, \b and so forth). So it may seem odd if you're not used to it, but it is actually perfectly logical if you think of it in the Vim way.
1 I've tested this in both TextMate and SublimeText and it works as-is, but some editors use \1 instead of $1. Try both and see which your editor uses.
2 I just pulled this regex out of my history. I always tweak regexen while using them, and I can't promise this the final version, so I'm not suggesting it's fit for the purpose described, and especially not with SQL formatted differently from the SQL I was working on, just that it's a specific example of downcasing in regular expressions. YMMV. UAYOR.
Several answers have noted the use of \L. However, \E is also worth knowing about if you use \L.
\L converts everything up to the next \U or \E to lowercase. ... \E turns off case conversion.
(Source: https://www.regular-expressions.info/replacecase.html )
So, suppose you wanted to use rename to lowercase part of some file names like this:
artist_-_album_-_Song_Title_to_be_Lowercased_-_MultiCaseHash.m4a
artist_-_album_-_Another_Song_Title_to_be_Lowercased_-_MultiCaseHash.m4a
you could do something like:
rename -v 's/^(.*_-_)(.*)(_-_.*.m4a)/$1\L$2\E$3/g' *
In Perl, there's
$string =~ tr/[A-Z]/[a-z]/;
Most Regex implementations allow you to pass a callback function when doing a replace, hence you can simply return a lowercase version of the match from the callback.