I am trying to validate a string with the following specification:
"Non-empty string that contains only letters, dashes, or single quotes"
I'm using String.matches("[a-zA-Z|-|']*") but it's not catching the - characters correctly. For example:
Test Result Should Be
==============================
shouldpass true true
fail3 false false
&fail false false
pass-pass false true
pass'again true true
-'-'-pass false true
So "pass-pass" and "-'-'-pass" are failing. What am I doing wrong with my regex?
You should use the following regex:
[a-zA-Z'-]+
You regex is allowing literal |, and you have a range specified, from | to |. The hyphen must be placed at the end or beginning of the character class, or escaped in the middle if you want to match a literal hyphen. The + quantificator at the end will ensure the string is non-empty.
Another alternative is to include all Unicode letters:
[\p{L}'-]+
Java string: "[\\p{L}'-]+".
Possible solution:
[a-zA-Z-']+
Problems with your regex:
If you don't want to accept empty strings, change * to + to accept one or more characters instead of zero or more.
Characters in character class are implicitly separated by OR operator. For instance:
regex [abc] is equivalent of this regex a|b|c.
So as you see regex engine doesn't need OR operator there, which means that | will be treated as simple pipe literal:
[a|b] represents a OR | OR b characters
You seem to know that - has special meaning in character class, which is to create range of characters like a-z. This means that |-| will be treated by regex engine as range of characters between | and | (which effectively is only one character: |) which looks like main problem of your regex.
To create - literal we either need to
escape it \-
place it where - wouldn't be able to be interpreted as range. To be more precise we need to place it somewhere where it will not have access to characters which could be use as left and right range indicators l-r like:
at start of character class [- ...] (no left range character)
at end of character class [... -] (no right range character)
right after other range like A-Z-x - Z was already used as character representing end of range A-Z so it can't reused in Z-x range.
This will work:
[a-zA-Z'-]+
Using the | is going to search for a range, you just want that specific character.
Tested Here
try {
if (subjectString.matches("(?i)([a-z'-]+)")) {
// String matched entirely
} else {
// Match attempt failed
}
} catch (PatternSyntaxException ex) {
// Syntax error in the regular expression
}
EXPLANATION:
(?i)([a-z'-]+)
----------
Options: Case insensitive; Exact spacing; Dot doesn't match line breaks; ^$ don't match at line breaks; Default line breaks
Match the regex below and capture its match into backreference number 1 «([a-z'-]+)»
Match a single character present in the list below «[a-z'-]+»
Between one and unlimited times, as many times as possible, giving back as needed (greedy) «+»
A character in the range between “a” and “z” (case insensitive) «a-z»
The literal character “'” «'»
The literal character “-” «-»
Related
This question already has answers here:
Java RegEx meta character (.) and ordinary dot?
(9 answers)
Closed 2 years ago.
Upon validation using regular expression in Java, I need to return true for height having values :
80cm
80.2cm
80.25cm
My regular expression is as follows :
(\d)(\d?)(.?)(\d?)(\d?)(c)(m)
However if I pass in height as 71-80cm , the regular expression returns true too.
What change should I make to the regular expression to return false when height is 71-80cm ?
. matches any character, so you need to have \\. or just \. depending on the source. Check out: Java RegEx meta character (.) and ordinary dot?
Furthermore, additional changes need to be made such that e.g. 8025cm is not accepted if that is what you want.
I assume that the OP wishes to match substrings of the form
abcm
where:
"cm" is a literal;
"cm" is not followed by a letter;
"b" is the string representation of a non-negative float or integer (e.g., "80" or "80.25", but not "08" or ".25"); and
"a" is a character other than "-", "+" and ".", unless "b" is at the beginning of the string, in which case "a" is an empty string.
If my assumptions are correct you could use the following regex to match b in abcm:
(?<![-+.\d])[1-9]\d*(?:\.\d+)?cm(?![a-zA-Z])
Demo
The regex engine performs the following operations:
(?<! # begin negative lookbehind
[-+.\d] # match '-', '+', '.' or a digit
) # end negative lookbehind
[1-9] # match digit other than zero
\d* # match 0+ digits
(?:\.\d+) # match '.' followed by 1+ digits in a non-cap grp
? # optionally match non-cap grp
cm # match 'cm'
(?![a-zA-Z]) # match a letter in a negative lookahead
If my assumptions about what is required are not correct it may be evident how my answer could be adjusted appropriately.
Ok, let's take your expression and clean it up a little. You don't need all the capturing groups (..), since all you're interested in is validating the complete string. For that reason you should also enclose the expression in line beginning ^ and line end $ anchors, so your expression can't match inside a larger string. Lastly, you can group the period and trailing digits together (?:), since you won't get one without the other as per your example data. Which gets us:
^\d\d?(?:\.\d\d?)?cm$
See regex demo.
Then in Java, that check could look like this:
boolean foundMatch = subjectString.matches("^\\d\\d?(?:\\.\\d\\d?)?cm$");
I have this format: xx:xx:xx or xx:xx:xx-y, where x can be 0-9 a-f A-F and y can be only 0 or 1.
I come up with this regex: ([0-9A-Fa-f]{2}[:][0-9A-Fa-f]{2}[:][0-9A-Fa-f]{2}|[-][0-1]{1})
(See regexr).
But this matches 0a:0b:0c-3 too, which is not expected.
Is there any way to remove these cases from result?
[:] means a character from the list that contains only :. It is the same as
:. The same for [-] which has the same result as -.
Also, {1} means "the previous piece exactly one time". It does not have any effect, you can remove it altogether.
To match xx:xx:xx or xx:xx:xx-y, the part that matches -y must be optional. The quantifier ? after the optional part mark it as optional.
All in all, your regex should be like this:
[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}(-[01])?
If the regex engine you use can be told to ignore the character case then you can get rid of A-F (or a-f) from all character classes and the regex becomes:
[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}(-[01])?
How it works, piece by piece:
[0-9a-f] # any digit or letter from (and including) 'a' to 'f'
{2} # the previous piece exactly 2 times
: # the character ':'
[0-9a-f]
{2}
:
[0-9a-f]
{2}
( # start a group; it does not match anything
- # the character '-'
[01] # any character from the class (i.e. '0' or '1')
) # end of group; the group is needed for the next quantifier
? # the previous piece (i.e. the group) is optional
# it can appear zero or one times
See it in action: https://regexr.com/4rfvr
Update
As #the-fourth-bird mentions in a comment, if the regex must match the entire string then you need to anchor its ends:
^[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}(-[01])?$
^ as the first character of a regex matches the beginning of the string, $ as the last character matches the end of the string. This way the regex matches the entire string only (when there aren't other characters before or after the xx:xx:xx or xx:xx:xx-y part).
If you use the regex to find xx:xx:xx or xx:xx:xx-y in a larger string then you don't need to add ^ and $. Of course, you can add only ^ or $ to let the regex match only at the beginning or at the end of the string.
You want
xx:xx:xx or if it is followed by a -, then it must be a 0 or 1 and then it is the end (word boundry).
So you don't want any of these
0a:0b:0c-123
0a:0b:0cd
10a:0b:0c
either.
Then you want "negative lookingahead", so if you match the first part, you don't want it to be followed by a - (the first pattern) and it should end there (word boundary), and if it is followed by a -, then it must be a 0 or 1, and then a word boundary:
/\b([0-9a-f]{2}[:][0-9a-f]{2}[:][0-9a-f]{2}(?!-)\b|\b[0-9a-f]{2}[:][0-9a-f]{2}[:][0-9a-f]{2}-[01]\b)/i
To prevent any digit in front, a word boundary is added to the front as well.
Example: https://regexr.com/4rg42
The following almost worked:
/\b([0-9a-f]{2}[:][0-9a-f]{2}[:][0-9a-f]{2}\b[^-]|\b[0-9a-f]{2}[:][0-9a-f]{2}[:][0-9a-f]{2}-[01]\b)/i
but if it is the end of file and it is 3a:2b:11, then the [^-] will try to match a non - character and it won't match.
Example: https://regexr.com/4rg4q
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:
I came up to a line in java that uses regular expressions.
It needs a user input of Last Name
return lastName.matches( "[a-zA-z]+([ '-][a-zA-Z]+)*" );
I would like to know what is the function of the [ '-].
Also why do we need both a "+" and a "*" at the same time, and the [ '-][a-zA-Z] is in brackets?
Your RE is: [a-zA-z]+([ '-][a-zA-Z]+)*
I'll break it down into its component parts:
[a-zA-Z]+
The string must begin with any letter, a-z or A-Z, repeated one or more times (+).
([ '-][a-zA-Z]+)*
[ '-]
Any single character of <space>, ', or -.
[a-zA-Z]+
Again, any letter, a-z or A-Z, repeated once or more times.
This combination of letters ('- and a-ZA-Z) may then be repeated zero or more times.
Why [ '-]? To allow for hiphenated names, such as Higgs-Boson or names with apostrophes, such as O'Reilly, or names with spaces such as Van Dyke.
The expression [ '-] means "one of ', , or -". The order is very important - the dash must be the last one, otherwise the character class would be considered a range, and other characters with code points between the space and the quote ' would be accepted as well.
+ means "one or more repetitions"; * means "zero or more repetitions", referring to the term of the regular expression preceding the + or * modifier.]
Overall, the expression matches groups of lowercase and uppercase letters separated by spaces, dashes, or single quotes.
it means it can be any of the characters space ' or - ( space, quote dash )
the - can be done as \- as it also can mean a range... like a-z
This looks like it is a pattern to match double-barreled (space or hyphen) or I-don't-know-what-to-call-it names like O'Grady... for example:
It would match
counter-terrorism
De'ville
O'Grady
smith-jones
smith and wesson
But it will not match
jones-
O'Learys'
#hashtag
Bob & Sons
The idea is, after the first [A-Za-z]+ consumes all the letters it can, the match will end right there unless the next character is a space, an apostrophe, or a hyphen ([ '-]). If one of those characters is present, it must be followed by at least one more letter.
A lot of people have difficulty with this. The naively write something like [A-Za-z]+[ '-]?[A-Za-z]*, figuring both the separator and the extra chunks of letters are optional. But they're not independently optional; if there is a separator ([ '-]), it must be followed by at least one more letter. Otherwise it would treat strings like R'- j'-' as valid. Your regex doesn't have that problem.
By the way, you've got a typo in your regex: [a-zA-z]. You want to watch out for that, because [A-z] does match all the uppercase and lowercase letters, so it will seem to be working correctly as long as the inputs are valid. But it also matches several non-letter characters whose code points happen to lie between those of Z and a. And very few IDEs or regex tools will catch that error.
I had this regex in java that matched either an alphanumeric character or the tilde (~)
^([a-z0-9])+|~$
Now I have to add also the characters - and _ I've tried a few combinations, neither of which work, for example:
^([a-zA-Z0-9_-])+|~$
^([a-zA-Z0-9]|-|_)+|~$
Sample input strings that must match:
woZOQNVddd
00000
ncnW0mL14-
dEowBO_Eu7
7MyG4XqFz-
A8ft-y6hDu
~
Any clues / suggestion?
- is a special character within square brackets. It indicates a range. If it's not at either end of the regex it needs to be escaped by putting a \ before it.
It's worth pointing out a shortcut: \w is equivalent to [0-9a-zA-Z_] so I think this is more readable:
^([\w-]+|~$
You need to escape the -, like \-, since it is a special character (the range operator). _ is ok.
So ^([a-z0-9_\-])+|~$.
Edit: your last input String will not match because the regular expression you are using matches a string of alphanumeric characters (plus - and _) OR a tilde (because of the pipe). But not both. If you want to allow an optional tilde on the end, change to:
^([a-z0-9_\-])+(~?)$
If you put the - first, it won't be interpreted as the range indicator.
^([-a-zA-Z0-9_])+|~$
This matches all of your examples except the last one using the following code:
String str = "A8ft-y6hDu ~";
System.out.println("Result: " + str.matches("^([-a-zA-Z0-9_])+|~$"));
That last example won't match because it doesn't fit your description. The regex will match any combination of alphanumerics, -, and _, OR a ~ character.