Java regular expression to match integers from user input - java

I'm trying to improve my regex skills, so I have made a basic calculator to practice pattern matching. The user is prompted to enter two integer values into the console, separated by a comma, with no spaces. I'm not worried about the values being too large for int to handle, I just want to cover the case of user entering -0. Positive 0, and all other negative and positive values should be accepted.
A scanner object grabs the input from the user and stores it in a string variable. This variable is then passed to a method with a Pattern and Matcher that does the matching and returns a boolean of whether it matched or not.
String userInput = scanner.next();
//look for only integers, especially excluding -0
if(checkUserMathInputIsGood("REGEX", userInput))
{
int sum;
String[] twoNumbersToAdd = userInput.split(",");
sum = Integer.parseInt(twoNumbersToAdd[0]) + Integer.parseInt(twoNumbersToAdd[1]);
System.out.println(sum);
}
After hours of scouring stackoverflow, javadocs, etc., I've found some solutions which almost work.
http://www.vogella.com/tutorials/JavaRegularExpressions/article.html#regex_negative
http://www.regexplanet.com/advanced/java/index.html
Java regular expression for negative numbers?
The pattern example which begins with "T(blah blah)" didn't work at all, and I can't find a reference to what T is supposed to accomplish. I've come close with:
"-{0,1}(?!0)\\d+,-{0,1}(?!0)\\d+"
Breaking it down, this seems to say: allow a minus sign a minimum of 0 and maximum of 1 times. Do not allow 0 if the so-called "negative lookahead" for the minus sign is true. Then allow any integer value at least one integer long. However, this results in the regex rejecting 0 as well as -0.
Examples of input which should be accepted:
2,3
22,-4
-555,-9
0,88
0,0
Examples of input which should be rejected:
-0,9
432,-0
-0,-0
Any help or suggestions is greatly appreciated.

If I understood the requirements correctly then it should be "-?\\d+,-?\\d+"

^(?:(?:\+?\d+)|(?:-(?!0*,)\d+)),(?:(?:\+?\d+)|(?:-(?!0*$)\d+))$
Demo.
Explanation:
^// match start of line or text
(?:// match either:
(?:// option 1:
\+? // a "+" if possible
\d+ // and any number of digits
)
|// or
(?:// option 2:
- // a "-" sign
(?!//negative lookahead assertion: do NOT match if next is...
0*,//...any number of zeroes and a comma
)
\d+//if we've made it this far, then we know this integer is NOT zero. Match any number of digits.
)
)
,// a comma.
(?:// this pattern is basically the same as the one for the first number.
(?:
\+?
\d+
)
|
(?:
-
(?!
0*$// except this matches the end of a line or text instead of a comma.
)
\d+
)
)
$// end of line or text.

Related

Having difficulty understanding Java regex interpretation [duplicate]

This question already has an answer here:
Reference - What does this regex mean?
(1 answer)
Closed 3 years ago.
Can someone help me with the following Java regex expression? I've done some research but I'm having a hard time putting everything together.
The regex:
"^-?\\d+$"
My understandning of what each symbol does:
" = matches the beginning of the line
- = indicates a range
? = does not occur or occurs once
\\d = matches the digits
+ = matches one or more of the previous thing.
$ = matches end of the line
Is the regex saying it only want matches that start or end with digits? But where do - and ? come in?
- only indicates a range if it's within a character class (i.e. square brackets []). Otherwise, it's a normal character like any other. With that in mind, this regex matches the following examples:
"-2"
"3"
"-700"
"436"
That is, a positive or negative integer: at least one digit, optionally preceded by a minus sign.
Some regex is composed, as you have now, the correct way to read your regex is :
^ start of word
-? optional minus character
\\d+ one or more digits
$ end of word
This regex match any positive or negative numbers, like 0, -15, 558, -19663, ...
Fore details check this good post Reference - What does this regex mean?
"^-?\\d+$" is not a regex, it's a Java string literal.
Once the compiler has parsed the string literal, the string value is ^-?\d+$, which is a regex matching like this:
^ Matches beginning of input
- Matches a minus sign
? Makes previous match (minus sign) optional
\d Matches a digit (0-9)
+ Makes previous match (digit) match repeatedly (1 or more times)
$ Matches end of input
All-in-all, the regex matches a positive or negative integer number of unlimited length.
Note: A - only denotes a range when inside a [] character class, e.g. [4-7] is the range of characters between '4' and '7', while [3-] and [-3] are not ranges since the start/end value is missing, so they both just match a 3 or - character.

Why does this regex not match

I'm building a regex pattern to validate my String inputted.
Here is the limitations that i have to include;
The letters a to z (upper and lowercase) (zero or many times)
o The numbers 0 to 9 (between zero and three times)
o The ampersand (&) character (zero or may times)
o The space character (zero or one time)
Here is the regex I built and tested on
[a-zA-Z&]*|[0-9]{0,3}|[\s]?
String p1 = "[a-zA-Z\\&]*|[0-9]{0,3}|[\\s]?" ;
if (bankName.matches(p1) && bankName.length() >= 8) {
System.out.println("Yes");
}
else{
System.out.println("NO");
}
Here is the entries I'm testing against.
tXiPkaodan57yzrCxYjVT
String bankName = "tXiPkaodan57yzrCxYjVT" ;
On the site i'm testing the regex on is not matching because the numbers ( 5 & 7 ) started and is between the letters but I have included in my regex pattern that it should beable to include any numbers range from 0-9, and 0-3 times
https://www.freeformatter.com/java-regex-tester.html#ad-output
The site i tested it on
The bars ('or') in your regexes have the most precedence, so, that regexp reads:
Match if the input is precisely one of:
Either 0 or more characters that ALL match any letter (either case) or an ampersand,
anywhere between 0 and 3 digits
0 or 1 space.
Your input is none of those things; it is a mix of those things. For example, the input 'a1a' does not match your regexp because, well, step through it: the 'a' forces the regexp matcher to pick the first of your 3 options above, and that's.. it. There's no going back now. Your regexp will match the a, fails to match on the 1, and that's the end of it.
So, how do you fix it? Not by sticking with regexp; that's not good solution for this problem. A regexp that precisely does what you asked for is very convoluted.
Instead, why not just loop through each character, and have 4 counters (spaces, digits, letters, and other stuff). For each character increment the right counter. Then at the end, check that the 'other stuff' counter is 0, digits is 3 or less, and spaces is 1 or less, and then it is valid. Otherwise, it is not.

minimum number in a string should be 1 regex validation?

I have a String which I need to match. Meaning it should only contains a number followed by space or just a number and minimum number should be 1 always. For ex:
3 1 2
1 p 3
6 3 2
0 3 2
First and third are valid string and all other are not.
I came up with below regex but I am not sure how can I check for minimum number in that string should be 1 always?
str.matches("(\\d|\\s)+")
Regex used from here
Just replace \\d with [1-9].
\\d is just a shorthand for the class [0-9].
This is a better regex though: ([1-9]\\s)*[1-9]$, as it takes care of double digit issues and won't allow space at the end.
Not everything can or should be solved with regular expressions.
You could use a simple expression like
str.matches("((\\d+)\\s)+")
or something alike to simply check that your input line contains only groups of digits followed by one or more spaces.
If that matches, you split along the spaces and for each group of digits you turn it into a number and validate against the valid range.
I have a gut feeling that regular expressions are actually not sufficient for the kind of validation you need.
If it should only contains a number followed by space or just a number and minimum number should be 1 and number can also be larger than 10 you might use:
^[1-9]\\d*(?: [1-9]\\d*)*$
Note that if you want to match a space only, instead of using \s which matches more you could just add a space in the pattern.
Explanation
^ Assert the start of the string
[1-9]\\d* Match a number from 1 up
(?: [1-9]\\d*)* Repeat a number from 1 up with a prepended space
$ Assert end of the string
Regex demo
Regex is part of the solution. But I don't think that regex alone can solve your problem.
This is my proposed solution:
private static boolean isValid(String str) {
Pattern pattern = Pattern.compile("[(\\d+)\\s]+");
Matcher matcher = pattern.matcher(str);
return matcher.matches() && Arrays.stream(Arrays.stream(matcher.group().split(" "))
.mapToInt(Integer::parseInt)
.toArray()).min().getAsInt() == 1;
}
Pay attention to the mathing type: matcher.matches() - to check match against the entire input. (don't use matcher.find() - because it will not reject invalid input such as "1 p 2")

Can you fix this Java Regex to match currency such as -10 USD, 12.35 AUD ... (Java)?

I have a need to validate the Currency String as followings:
1. The Currency Unit must be in Uppercase and must contain 3 characters from A to Z
2. The number can contain negative (-) or positive (+) sign.
3. The number can contain the decimal fraction, but if the number contain
the decimal fraction then the fraction must be 2 Decimal only.
4. There is no space in the number part
So see this example:
10 USD ------> match
+10 USD ------> match
-10 USD ------> match
10.23 AUD ------> match
-12.11 FRC ------> match
- 11.11 USD ------> NOT match because there is space between negative sign and the number
10 AUD ------> NOT match because there is 2 spaces between the number and currency unit
135.1 AUD ------> NOT match because there is only 1 Decimal in the fraction
126.33 YE ------> NOT match because the currency unit must contain 3 Uppercase characters
So here is what I tried but failed
if(text != null && text.matches("^[+-]\\d+[\\.\\d{2}] [A-Z]{3}$")){
return true;
}
The "^\\d+ [A-Z]{3}$" only match number without any sign and decimal part.
So Can you fix this Java Regex to match currency that meets the above requirements?
Some other questions in the internet do not match my requirements.
It seems you don't know about ? quantifier which means that element which this quantifier describes can appear zero times or once, making it optional.
So to say that string can contain optional - or + at start just add [-+]?.
To say that it can contain optional decimal part in form .XX where X would be digit just add (\\.\\d{2})?
So try with "^[-+]?\\d+(\\.\\d{2})? [A-Z]{3}$"
BTW If you are using yourString.matches(regex) then you don't have to add ^ or $ to regex. This method will match only if entire string will match regex so these metacharacters are not necessary.
BTW2 Normally you should escape - in character class [...] because it represents range of characters like [A-Z] but in this case - can't be used this way because it is at start of character class so there is no "first" range character, so you don't have to escape - here. Same goes if - is last character in [..-]. Here it also can't represent range so it is simple literal.
Try with:
text.matches("[+-]?\\d+(\\.\\d\\d)? [A-Z]{3}")
Note that since you use .matches(), the regex is automatically anchored (blame the Java API desingers for that: .matches() is woefully misnamed)
you could start your regex with
^(\\+|\\-)?
Which means that it will accept either one + sign, one - sign or nothing at all before the digit. But that's only one of your problems.
Now the decimal point:
"3. The number can contain the decimal fraction, but if the number contain
the decimal fraction then the fraction must be 2 Decimal only."
so after the digit \\d+ the next part should be in ( )? to indicate that it is optional (meaning 1 time or never). So either there are exactly one dot and two digits or nothing
(\\.\\d{2})?
Here you can find a reference for regex and test them. Just have a look at what else you could use to identify the 3 Letters for the currency. E.g. the \s could help you to identify a whitespace
This will match all your cases:
^[-+]?\d+(\.\d{2})?\s[A-Z]{3}$
(Demo # regex101)
To use it in Java you have to escape the \:
text.matches("^[-+]?\\d+(\\.\\d{2})?\\s[A-Z]{3}$")
Your regex wasn't far from the goal, but it contains several mistakes.
The most important one is: [] denotes a character class while () is a capturing group. So when you specify a character group like [\\.\\d{2}] it will match on the characters \,.,d,{,2, and}, while you want to match on the pattern .\d{2}.
The other answers already taught you the ? quantifier, so I won't repeat this.
On a sidenote: regular-expressions.info is a great source to learn these things!
Explanation of the regex used above:
^ #start of the string/line
[-+]? #optionally a - or a + (but not both; only one character)
\d+ #one or more numbers
( #start of optional capturing group
\.\d{2} #the character . followed by exactly two numbers (everything optional)
)? #end of optional capturing group
\s #a whitespace
[A-Z]{3} #three characters in the range from A-Z (no lowercase)
$ #end of the string/line

Match a possibly negative number that may or may not be double

I am building a temperature converter in Java. The user will input a number into a JTextField, pick their starting label using a JComboBox, and pick their ending label using JRadioButtons in a ButtonGroup. The number that the user enters can be of varying possiblities. It can be
A single integer, such as 5
A multiple integer, such as 55
A double, such as 5.5
A negative version of any of the above, such as -5, -55, or -5.5
The JTextField has a method getText(), which returns the value of the string. This is then converted to a double, and finally converted to the desired ending label. Because the String has to be converted to a double, alpha characters can't be allowed in the JTextField. So I am using regex to solve this. I currently have
String tempV = startTempValInput.getText();
if (tempV.matches("-?[0-9]+\\.[0-9]+")) {
// Code Here
}
However, this doesn't recognize single or multiple integers. How can I modify this to include integers?
tempV.matches("-?[0-9]+(\\.[0-9]+)?")
Breaking it down:
-? - This will match a negative number 0 or 1 time
[0-9]+ - This will match a numeric character 1 or more times
(\\.[0-9]+)? - This will match a possible decimal place to infinity
\\. - This will match a period. The double escape is needed, because Java recognizes Regexes as normal strings. This means you have to escape the backslash
[0-9]+ - This will match a numeric character 1 or more times
This is all wrapped in ()? because it is optional to have a decimal place. If you were to try -?[0-9]+\\.?[0-9]+ instead, it would not recognize a single integer. It would see the negative and period as optional, but since + returns 1 or more, it would require at least two integers.
An alternative would be
tempV.matches("-?([0-9]+\\.)?[0-9]+")
Because the String has to be converted to a double, alpha characters can't be allowed in the JTextField
What about 2.0E3?
I would just use Double.parseDouble, and catch the NumberFormatException:
try {
Double.parseDouble(inStr);
} catch (NumberFormatException e) {
// string doesn't represent a double
}
You could do it yourself with a regex, but there are various edge cases to consider: scientific notation (as shown above), a leading +, etc. It's certainly manageable, but why write code to accomplish something that's already done for you?
A pattern that catches a broad range of double input is:
^(?![+-]$|[-+]E|E|$|\.$)[+-]?\d*(\.?\d*)?(E-?\d+)?$
which matches edge cases of:
1
1.
.1
4E7
3.4E-5
+7.4
-5
See a live demo.
Because every term is optional, the negative look ahead is needed to catch degenerate cases that would otherwise match.
Note that this regex does not prevent over/under flow, eg 1E9999, which is too large for double to represent.
You could cover all the bases with this possibly:
edit - ensure a digit somewhere, thanks #yshavit
^(?=\D*\d)(?=[\d.-]+$)-?\d*\.?\d*$
Could be extended to cover more as well:
modified - Simplified version, some assertions are not needed.
# (?i)^(?=[^e]*\d)[+-]?\d*\.?\d*(?:e[+-]?\d+)?$
# "(?i)^(?=[^e]*\\d)[+-]?\\d*\\.?\\d*(?:e[+-]?\\d+)?$"
(?i) # Case insensitive modifier
^ # Beginning of string
(?= [^e]* \d ) # Lookahead must be a digit (and before exponent)
[+-]? \d* \.? \d* # Consume correct numeric form
(?: e [+-]? \d+ )? # Consume correct exponent form
$ # End of string

Categories