Having problems with java regex - java

I have the following regex:
/[-A-Z]{4}\d{2}/[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}.png
Basically I want to check for strings of the basic type
ABCD12/<here_is_a_random_uuid_as_a_string>.png
The UUID (which is in UPPER CASE) checking works fine, but now let's take a look at a special case. I want to accept strings like this
--CD12/...
AB--12/...
but NOT like this:
A--D12/...
But I can not get the first part of the regex right. Basically I need to check for either two digits or two -after each other twice.
For my understanding [-A-Z]{4} means "either - or something between A - Z with a length of 4". So why doesn't my pattern work?
EDIT:
This answer was posted within the comments and it works:
(?mi)^(?:--[A-Z]{2}|[A-Z]{2}(?:--|[A-Z]{2}))\d{2}/[0-9A-F]{8}(?:-[0-9A-F]{4}){3}-[0-9A-F]{12}\.png$
Can somebody explain to me what (?mi) and what (?:...) means? The normal ? means 0 or 1 time, but what is the : for?
EDIT 2:
Just for those how might have a similar problem and do not want to read all of those regexes ;)
I slightly modified an answer to also accept patterns like ----12. The end result:
"^/(?:--[A-Z]{2}|-{4}|[A-Z]{2}(?:--|[A-Z]{2}))\\d{2}/[0-9A-F]{8}(?:-[0-9A-F]{4}){3}-[0-9A-F]{12}\\.png$"
It works like a charm.

You may use this regex for your cases:
^(?:--[A-Z]{2}|[A-Z]{2}(?:--|[A-Z]{2}))\d{2}/[0-9A-F]{8}(?:-[0-9A-F]{4}){3}-[0-9A-F]{12}\.png$
RegEx Demo
Details about first part:
^: Start
(?:: Start non-capture group
--[A-Z]{2}: Match -- followed by 2 letters
|: OR
[A-Z]{2}: Match 2 letters
(?:--|[A-Z]{2}): Match -- OR 2 letters
): End non-capture group
btw (?:...) is non-capture group.

Your [-A-Z]{4} matches any four occurrences of an uppercase ASCII letter or -, so it can also match ----, A---, ---B, -B--, etc.
You want to make sure that if there are hyphens, they come after or before two letters:
(?:[A-Z]{2}--|--[A-Z]{2}|[A-Z]{4})
It means:
(?: - start of a non-capturing group:
[A-Z]{2}-- - two uppercase ASCII letters and then --
| - or
--[A-Z]{2} - -- and then any two uppercase ASCII letters
| - or
[A-Z]{4} - any four uppercase ASCII letters
) - end of the non-capturing group.
The full pattern:
(?:[A-Z]{2}--|--[A-Z]{2}|[A-Z]{4})\d{2}/[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}\.png
To force the entire string match, add ^ (start of string) and $ (end of string) anchors:
^(?:[A-Z]{2}--|--[A-Z]{2}|[A-Z]{4})\d{2}/[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}\.png$
See the regex demo
Note the . matches any char, to match a literal dot, you should escape it.

Related

Regex pattern matching with multiple strings

Forgive me. I am not familiarized much with Regex patterns.
I have created a regex pattern as below.
String regex = Pattern.quote(value) + ", [NnoneOoff0-9\\-\\+\\/]+|[NnoneOoff0-9\\-\\+\\/]+, "
+ Pattern.quote(value);
This regex pattern is failing with 2 different set of strings.
value = "207e/160";
Use Case 1 -
When channelStr = "207e/160, 149/80"
Then channelStr.matches(regex), returns "true".
Use Case 2 -
When channelStr = "207e/160, 149/80, 11"
Then channelStr.matches(regex), returns "false".
Not able to figure out why? As far I can understand it may be because of the multiple spaces involved when more than 2 strings are present with separated by comma.
Not sure what should be correct pattern I should write for more than 2 strings.
Any help will be appreciated.
If you print your pattern, it is:
\Q207e/160\E, [NnoneOoff0-9\-\+\/]+|[NnoneOoff0-9\-\+\/]+, \Q207e/160\E
It consists of an alternation | matching a mandatory comma as well on the left as on the right side.
Using matches(), should match the whole string and that is the case for 207e/160, 149/80 so that is a match.
Only for this string 207e/160, 149/80, 11 there are 2 comma's, so you do get a partial match for the first part of the string, but you don't match the whole string so matches() returns false.
See the matches in this regex demo.
To match all the values, you can use a repeating pattern:
^[NnoeOf0-9+/-]+(?:,\h*[NnoeOf0-90+/-]+)*$
^ Start of string
[NnoeOf0-9\\+/-]+
(?: Non capture group
,\h* Match a comma and optional horizontal whitespace chars
[NnoeOf0-90-9\\+/-]+ Match 1+ any of the listed in the character class
)* Close the non capture group and optionally repeat it (if there should be at least 1 comma, then the quantifier can be + instead of *)
$ End of string
Regex demo
Example using matches():
String channelStr1 = "207e/160, 149/80";
String channelStr2 = "207e/160, 149/80, 11";
String regex = "^[NnoeOf0-9+/-]+(?:,\\h*[NnoeOf0-90+/-]+)*$";
System.out.println(channelStr1.matches(regex));
System.out.println(channelStr2.matches(regex));
Output
true
true
Note that in the character class you can put - at the end not having to escape it, and the + and / also does not have to be escaped.
You can use regex101 to test your RegEx. it has a description of everything that's going on to help with debugging. They have a quick reference section bottom right that you can use to figure out what you can do with examples and stuff.
A few things, you can add literals with \, so \" for a literal double quote.
If you want the pattern to be one or more of something, you would use +. These are called quantifiers and can be applied to groups, tokens, etc. The token for a whitespace character is \s. So, one or more whitespace characters would be \s+.
It's difficult to tell exactly what you're trying to do, but hopefully pointing you to regex101 will help. If you want to provide examples of the current RegEx you have, what you want to match and then the strings you're using to test it I'll be happy to provide you with an example.
^(?:[NnoneOoff0-9\\-\\+\\/]+ *(?:, *(?!$)|$))+$
^ Start
(?: ... ) Non-capturing group that defines an item and its separator. After each item, except the last, the separator (,) must appear. Spaces (one, several, or none) can appear before and after the comma, which is specified with *. This group can appear one or more times to the end of the string, as specified by the + quantifier after the group's closing parenthesis.
Regex101 Test

java regex to capture any number of periods within a string

I am trying to match on any of the following:
$tag:parent.child$
$tag:grand.parent.child$
$tag:great.grand.parent.child$
I have tried a bunch of combos but not sure how to do this without an exp for each one: https://regex101.com/r/cMvx9I/1
\$tag:[a-z]*\.[a-z]*\$
I know this is wrong, but haven't been able to find the right method yet. Help is greatly appreciated.
Your regex was: \$tag:[a-z]*\.[a-z]*\$
You need a repeating group of .name, so use: \$tag:[a-z]+(?:\.[a-z]+)+\$
That assumes there has to be at least 2 names. If only one name is allowed, i.e. no period, then change last + to *.
You can use \$tag:(?:[a-z]+\.)*[a-z]+\$
\$ a literal $
tag: literal tag:
(?:...) a non-capturing group of:
[a-z]+ one or more lower-case letters and
\. a literal dot
* any number of the previous group (including zero of them)
[a-z]+ one or more lower-case letters
\$ a literal $
The following pattern will match any periods within a string:
\.
Not sure if this is what you want, but you can make a non-capturing group out of a pattern and then find that a certain number of times:
\$tag:(?:[a-z]+?\.*){1,4}\$
\$tag: - Literal $tag:
(?:[a-z]+?\.*) - Non-capturing group of any word character one or more times (shortest match) followed by an optional literal period
{1,4} - The capturing group appears anywhere between 1-4 times (you can change this as needed, or use a simple + if it could be any number of times).
\$ - Literal $
I normally prefer \w instead of [a-z] as it is equivalent to [a-zA-Z0-9_], but using this depends on what you are trying to find.
Hope this helps.

Some more regex criteria in existing regex

I want to add into below regex which also pass following criteria -
^[\p{L}\d'][ \p{L}\d'-]*[\p{L}\d'-']$
Should start with letter (A-Z or a-z) only.
Can accepts only single letter also.
Accept hyphen (-), Space, dot (.) in between the string or end of the string. (No other special character)
Accept numbers in between and end to the string.
Please also want to achieve existing criteria what this regex is doing.
E.g.
Expected -
t, T, test, test123, te12st, te-st, te.st, te st, éééééé, ṪỲɎɆḂɃɀȿȸȺȔȐȳɊÉâÇë, Επίθετο
Not Expected -
12test, 1, .test, -test, , tes*t (none of the special character except hyphen, dot & space),
To match the expected and not the not expected including a single letter, you could match \pL from the start of the string. Then repeat 0+ times any of the listed in [\d\pL .-] and then assert the end of the string.
Note that not all of your expected start with a-zA-Z.
^\pL[\d\pL .-]*$
In Java
String regex = "^\\pL[\\d\\pL .-]*$";
Regex demo | Java demo
^[A-Za-z]+[\p{L}\d-.\s]*$
This is a possible solution, however these test criteria conflict with your first requirement: éééééé, ṪỲɎɆḂɃɀȿȸȺȔȐȳɊÉâÇë, Επίθετο. Where it 1) accepts one or more of A-Za-z then 2) zero or more combination of letters, numbers, hyphens, space, and periods.
If you want it to also accept those three test criteria then this is a possible solution:
^[\p{L}]+[\p{L}\d-.\s]*$

Restrict consecutive characters using Java Regex

I need to allow alphanumeric characters , "?","." , "/" and "-" in the given string. But I need to restrict consecutive - only.
For example:
www.google.com/flights-usa should be valid
www.google.com/flights--usa should be invalid
currently I'm using ^[a-zA-Z0-9\\/\\.\\?\\_\\-]+$.
Please suggest me how to restrict consecutive - only.
You may use grouping with quantifiers:
^[a-zA-Z0-9/.?_]+(?:-[a-zA-Z0-9/.?_]+)*$
See the regex demo
Details:
^ - start of string
[a-zA-Z0-9/.?_]+ - 1 or more characters from the set defined in the character class (can be replaced with [\w/.?]+)
(?:-[a-zA-Z0-9/.?_]+)* - zero or more sequences ((?:...)*) of:
- - hyphen
[a-zA-Z0-9/.?_]+ - see above
$ - end of string.
Or use a negative lookahead:
^(?!.*--)[a-zA-Z0-9/.?_-]+$
^^^^^^^^^
See the demo here
Details:
^ - start of string
(?!.*--) - a negative lookahead that will fail the match once the regex engine finds a -- substring after any 0+ chars other than a newline
[a-zA-Z0-9/.?_-]+ - 1 or more chars from the set defined in the character class
$ - end of string.
Note that [a-zA-Z0-9_] = \w if you do not use the Pattern.UNICODE_CHARACTER_CLASS flag. So, the first would look like "^[\\w/.?]+(?:-[\\w/.?]+)*$" and the second as "^(?!.*--)[\\w/.?-]+$".
One approach is to restrict multiple dashes with negative look-behind on a dash, like this:
^(?:[a-zA-Z0-9\/\.\?\_]|(?<!-)-)+$
The right side of the |, i.e. (?<!-)-, means "a dash, unless preceded by another dash".
Demo.
I'm not sure of the efficiency of this, but I believe this should work.
^([a-zA-Z0-9\/\.\?\_]|\-([^\-]|$))+$
For each character, this regex checks if it can match [a-zA-Z0-9\/\.\?\_], which is everything you included in your regex except the hyphen. If that does not match, it instead tries to match \-([^\-]|$), which matches a hyphen not followed by another hyphen, or a hyphen at the end of the string.
Here's a demo.

Match first occurrence of semicolon in string, only if not preceded by '--'

I'm trying to write a regular expression for Java that matches if there is a semicolon that does not have two (or more) leading '-' characters.
I'm only able to get the opposite working: A semicolon that has at least two leading '-' characters.
([\-]{2,}.*?;.*)
But I need something like
([^([\-]{2,})])*?;.*
I'm somehow not able to express 'not at least two - characters'.
Here are some examples I need to evaluate with the expression:
; -- a : should match
-- a ; : should not match
-- ; : should not match
--; : should not match
-;- : should match
---; : should not match
-- semicolon ; : should not match
bla ; bla : should match
bla : should not match (; is mandatory)
-;--; : should match (the first occuring semicolon must not have two or more consecutive leading '-')
It seems that this regex matches what you want
String regex = "[^-]*(-[^-]+)*-?;.*";
DEMO
Explanation: matches will accept string that:
[^-]* can start with non dash characters
(-[^-]+)*-?; is a bit tricky because before we will match ; we need to make sure that each - do not have another - after it so:
(-[^-]+)* each - have at least one non - character after it
-? or - was placed right before ;
;.* if earlier conditions ware fulfilled we can accept ; and any .* characters after it.
More readable version, but probably little slower
((?!--)[^;])*;.*
Explanation:
To make sure that there is ; in string we can use .*;.* in matches.
But we need to add some conditions to characters before first ;.
So to make sure that matched ; will be first one we can write such regex as
[^;]*;.*
which means:
[^;]* zero or more non semicolon characters
; first semicolon
.* zero or more of any characters (actually . can't match line separators like \n or \r)
So now all we need to do is make sure that character matched by [^;] is not part of --. To do so we can use look-around mechanisms for instance:
(?!--)[^;] before matching [^;] (?!--) checks that next two characters are not --, in other words character matched by [^;] can't be first - in series of two --
[^;](?<!--) checks if after matching [^;] regex engine will not be able to find -- if it will backtrack two positions, in other words [^;] can't be last character in series of --.
How about just splitting the string along -- and if there are two or more sub strings, checking if the last one contains a semicolon?
How about using this regex in Java:
[^;]*;(?<!--[^;]{0,999};).*
Only caveat is that it works with up to 999 character length between -- and ;
Java Regex Demo
I think this is what you're looking for:
^(?:(?!--).)*;.*$
In other words, match from the start of the string (^), zero or more characters (.*) followed by a semicolon. But replacing the dot with (?:(?!--).) causes it to match any character unless it's the beginning of a two-hyphen sequence (--).
If performance is an issue, you can exclude the semicolon as well, so it never has to backtrack:
^(?:(?!--|;).)*;.*$
EDIT: I just noticed your comment that the regex should work with the matches() method, so I padded it out with .*. The anchors aren't really necessary, but they do no harm.
You need a negative lookahead!
This regex will match any string which does not contain your original match pattern:
(?!-{2,}.*?;.*).*?;.*
This Regex matches a string which contains a semicolon, but not one occuring after 2 or more dashes.
Example:

Categories

Resources