String matches() method not working properly - java

So I have this method:
void verifySecretKey(String userEnters, Scanner input){
while(true) {
System.out.print("Enter the secret key: ");
userEnters = input.nextLine();
System.out.println("\nVerifying Secret Key...");
if (secretKey.matches(userEnters)) {
System.out.println("Secret key verified!");
break; }
else {
System.out.println("The secret key does not follow the proper format!"); }
}
}
and for some reason, it is not working properly. A string secretKey is automatically generated for the user and they must enter the exact string to be verified. However, even if the correct string was entered, it still says that it's incorrect.
Sometimes it works, and mostly it doesn't. I am wondering what I am doing wrong here?

String#matches accepts a string defining a regular expression. If you want to check for equality, use equals, not matches.
"oH-?bt-4#" contains a ?, which is a special character in regular expressions, not a literal ?. So the string doesn't match the regular expression.

Matches takes a regular expression as the argument. In the screenshot, you entered oH-?bt-4#, which contains a ?. This character has a special meaning in a regex. If you want to use the String#match method, you have to escape all the special characters, e. g. using Pattern.quote:
if (secretKey.matches(Pattern.quote(userEnters))) //...
Since your goal seems to be to check whether the two strings are the same, you could just use the String#equals method:
if (secretKey.equals(userEnters)) //...
When you don't have a reason to choose the regex-method matches, you should stick with equals, since it's more efficient.

According to the Javadoc,
public boolean matches(String regex)
Tells whether or not this string matches the given regular expression.
Now, "Java".matches("Java") is true, because the regex Java is a match for Java.
However there are lots of regexs that don't match themselves, and you're quite likely to find one if you generate strings randomly.
For example "a+bc".matches("a+bc") returns false -- because there's nothing there that matches the literal character + (a+ matches one-or-more as).
It's also very likely that a random string will result in something that can't be compiled as a regex, in which case your code will throw a PatternSyntaxException -- for example a[bc will do this because of an unmatched brace.
To test whether two strings are exactly the same, use .equals().

Related

How to get Pattern.matches(regex, str) to return false when str is dot (".")?

I would like to check if a string is a mathematical operator (+,-,*,/). I'm using the matches method to check the character against a regex but it always returns true when checking a string that contains only a dot ("."). Here's the code:
String dot = ".";
if(dot.matches("[*+-/]"))
System.out.println("BAD");
else
System.out.println("GOOD");
This prints "BAD". I get that it probably has to do with the fact that "." in regex matches everything but I don't see why that would make a difference. Is there any way to get this to return false? Thanks.
No, the String you invoke matches on is not considered a regular expression. It is taken literally.
Your case is printing BAD, because this [*+-/] is a character class where . falls between + and /. Move the - to the end so that it doesn't create a range, [*+/-].
I'm going to suggest a tool for going about this.
Try regexr, it's colorful, it's got help on the sidebar, and you will be able to write regexes better with all the cases you want and do not want to match.
To get you started, check out the really rudimentary regex written here: http://regexr.com/3af78.
\d [*+/-] \d
As I do not know how strict or loose you want your check to be, I've added additional strings that you may or may not want to consider.

Regex for String contains

I need to know whether a given string contains any of the characters *.=,? or :. I tried (using str.contains):
[*?=:] & also
[^*?=:] & also
^[*?=:]
None of them seem to work.
Could anyone let me know the regex to do it?
contains does not take a regex, but a simple String, as an argument. So in your example, it will look for this exact sequence of characters in your String: [*?=:]
You could instead use String.matches:
str.matches(".*[*.=,?:]+.*");
String.contains searches for the specified sequence of characters -- it does not use a regex. Instead, use:
s.matches(".*[*.=,?:].*")
This matches any string which consists of any characters, followed by one of the characters you mentioned, followed by any characters.
The method java.lang.String.contains(CharSequence) does not support regular expressions. You have to create your own little helper method.
To check if a String contains a Substring that matches a certain regex you can use a method like this:
/**
* Checks if the given string contains a substring that matches the given
* regex.
*/
public boolean checkStringContainsStringMatchingRegex(String pString, String pRegex) {
return Pattern.compile(pRegex).matcher(pString).find();
}
Difference to java.lang.String.matches(String):
String.matches(String) checks if the String matches the given regex
checkStringContainsStringMatchingRegex(String, String) checks if the String (first argument) contains a substring that matches the regex (second argument).

replaceAll type method that preserves special characters

Currently, the replaceAll method of the String class, along with Matcher.replaceAll methods evaluate their arguments as regular expressions.
The problem I am having is that the replacement string I am passing to either of these methods contains a dollar sign (which of course has special meaning in a regular expression). An easy work-around to this would be to pass my replacement string to 'Matcher.quoteReplacement' as this produces a string with literal characters, and then pass this sanitized string to replaceAll.
Unfortunately, I can't do the above as I need to preserve the special characters as the resultant string is later used in operations where a reg ex is expected, and if I have escaped all the special characters this will break that contract.
Can someone please suggest a way I might achieve what I want to do? Many thanks.
EDIT: For clearer explanation, please find code example below:
String key = "USD";
String value = "$";
String content = "The figure is in USD";
String contentAfterReplacement;
contentAfterReplacement = content.replaceAll(key, value); //will throw an exception as it will evaluate the $ in 'value' variable as special regex character
contentAfterReplacement = content.replaceAll(key, Matcher.quoteReplacement(value)); //Can't do this as contentAfterReplacement is passed on and later parsed as a regex (Ie, it can't have special characters escaped).
Why not use String#replace method instead of replaceAll. replaceAll uses regex but replace doesn't use regex in replacement string.

Java - regex not working

I have a string of "abc123(" and want to check if contains one or more chars that are not a number or character.
"abc123(".matches("[^a-zA-Z0-9]+"); should return true in this case? But it dose not! Whats wrong?
My test script:
public class NewClass {
public static void main(String[] args) {
if ("abc123(".matches("[^a-zA-Z0-9]+")) {
System.out.println("true");
}
}
}
In Java, the expressions has to match the entire string, not just part of it.
myString.matches("regex") returns true or false depending whether the
string can be matched entirely by the regular expression. It is
important to remember that String.matches() only returns true if the
entire string can be matched. In other words: "regex" is applied as if
you had written "^regex$" with start and end of string anchors. Source
Your expression is looking for part of the string, not the whole thing. You can change your expression to .*YOUR_EXPRESSION.* and it will expand to match the entire string.
Rather than checking to see if it contains only letters and numbers, why not check to see if it contains anything other than that? You can use the not word group (\W) and if that returns true than you know the string contains something other than the characters you are looking for,
"abc123(".matches("[\W]");
If this returns true than there is something other than just word characters and digits.
Expression [^A-Za-z0-9]+ means 'not letters or digits'. You probably want to replace it with ^[A-Za-z0-9]+$ which means 'Only letters or digits'.

Why the second argument is not being taken as regex?

I came across an interesting question on java regex
Is there a regular expression way to replace a set of characters with another set (like shell tr command)?
So I tried the following:
String a = "abc";
a = a.replaceAll("[a-z]", "[A-Z]");
Now if I get print a the output is
[A-Z][A-Z][A-Z]
Here I think the compiler is taking the first argument as gegex, but not the second argument.
So is there any problem with this code or something else is the reason???
This is the way replaceAll works.
See API:
public String replaceAll(String regex, String replacement)
Replaces each substring of this string that matches the given regular expression with the given replacement.
The answer to the linked question is a quite clear »No«, so this should come as no surprise.
As you can see from the documentation the second argument is indeed a regular string that is used as replacement:
Parameters:
regex – the regular expression to which this string is to be matched
replacement – the string to be substituted for each match
second argument is simple String that will get substituted according to API
If you want to turn lower case to upper case, there is a toUpperCase function available in String class. For equivalent functionality to tr utility, I think there is no support in Java (up to Java 7).
The replacement string is usually take literally, except for the sequence $n where n denotes the number of the capturing group in the regex. This will use captured string from the match as replacement.
I consider regex as a way to express a condition (i.e does a given string match this expression). With that in mind, what you are asking would mean "please replace what matches in my string with ... another condition" which doesn't make much sens.
Now by trying to understand what you are looking for, it ssems to me that you want to find some automatic mapping between classes of characters (e.g. [a-z] -> [A-Z]). As far as I know this does not exist and you would have to write it yourself (except for the forementionned toUpperCase())
public String replaceAll(String regex, String replacement)
First argument is regular expression if substring matches with that pattern that will be replaced by second argument ,if you want to convert to lowercase to upper case use
toUpperCase()
method
You should look into jtr. Example of usage:
String hello = "abccdefgdhcij";
CharacterReplacer characterReplacer;
try {
characterReplacer = new CharacterReplacer("a-j", "Helo, Wrd!");
hello = characterReplacer.doReplacement(hello);
} catch(CharacterParseException e) {
}
System.out.println(hello);
Output:
Hello, World!

Categories