Reputation: 175
I am trying to check if the height is valid. To be valid it must be 1 or 1.4 or 1.0 or 1. etc it cannot be anything else like a string, any chars beside a number or a decimal. The decimal must not be at the start of the string and it can only have 1 decimal. The regex I have been trying is:
"/^[0-9]+([\\,\\.][0-9]+)?$/"
But it is not working and still accepts strings. Any help would be great, thanks!
public static boolean HeightValid(String height)
{
boolean isHeightValid = true;
if(!height.matches("/^[0-9]+([\\,\\.][0-9]+)?$/") || height.length() < 1 || height.length() > 9)
{
isHeightValid = false;
}
else
{
double doubleHeight = Double.parseDouble(height);
DecimalFormat df = new DecimalFormat("#.00");
String decHeight = df.format(doubleHeight);
heightField.setText(decHeight);
}
return isHeightValid;
}
If you need any more information just add a comment, thank you
Upvotes: 3
Views: 8014
Reputation: 101
As sesquipedalias mentioned, the documentation for Double#valueOf(String) describes how to build a regular expression to match valid inputs. Still, the code provided in the documentation breaks just about every Java naming convention, and is inconveniently split into multiple lines. Minifying it into a single statement, we get
Pattern.compile("[\\x00-\\x20]*[+-]?(NaN|Infinity|((((\\d+)(\\.)?((\\d+)?)([eE][+-]?(\\d+))?)|(\\.((\\d+))([eE][+-]?(\\d+))?)|(((0[xX](\\p{XDigit}+)(\\.)?)|(0[xX](\\p{XDigit}+)?(\\.)(\\p{XDigit}+)))[pP][+-]?(\\d+)))[fFdD]?))[\\x00-\\x20]*")
I've taken the liberty of replacing the original \\p{Digit}
s with the shorter and equivalent \\d
.
Any input that matches this regular expression can be parsed into a Double using Double#parseDouble
. That being said, the expression does not necessarily cover all possible floating point literals in Java (as 12_23
for example is a perfectly valid literal in Java, but will throw a NumberFormatException
if passed to parseDouble
).
Here's an example:
import java.util.regex.Pattern;
public class Program {
public static final Pattern DOUBLE_PATTERN = Pattern.compile("[-+](Infinity|NaN|(0(x[\\da-fA-F]+|b[01]+)|(\\d+(_\\d+)*)(\\.(\\d+(_\\d+)*))?)([eE][-+]?\\d+)?[fFdD]?)");
public static void main(final String[] args) {
final String input = String.join(" ", args);
final boolean match = DOUBLE_PATTERN.matcher(input).matches();
System.out.println(match ? "It's a double!" : "Not a double...");
// This will never throw a NumberFormatException.
if (match) System.out.println("Value: " + Double.parseDouble(input));
}
}
Upvotes: 1
Reputation: 1
You can do a regular expression that strips undesired values with the values you wish to use and replace with a space. You can then split on the space and parse to a double. This is a solution for C#
new Regex(@"[^0-9.]+")
.Replace(stringWhichYouFilter, " ")
.Split(" ")
.Where(x => !string.IsNullOrWhiteSpace(x))
.Select(x =>
{
if (double.TryParse(x, out var doubleVal))
return doubleVal;
throw new InvalidCastException($"could not parse value '{x}' to a double");
})
Upvotes: 0
Reputation: 213
The java documentation gives you a regex for this purpose https://docs.oracle.com/javase/7/docs/api/java/lang/Double.html#valueOf(java.lang.String)
It's slightly more complicated than one might have hoped : ) Still, you could start here and make any ad-hoc changes you need in your specific case.
To avoid calling this method on an invalid string and having a NumberFormatException be thrown, the regular expression below can be used to screen the input string:
final String Digits = "(\\p{Digit}+)"; final String HexDigits = "(\\p{XDigit}+)"; // an exponent is 'e' or 'E' followed by an optionally // signed decimal integer. final String Exp = "[eE][+-]?"+Digits; final String fpRegex = ("[\\x00-\\x20]*"+ // Optional leading "whitespace" "[+-]?(" + // Optional sign character "NaN|" + // "NaN" string "Infinity|" + // "Infinity" string // A decimal floating-point string representing a finite positive // number without a leading sign has at most five basic pieces: // Digits . Digits ExponentPart FloatTypeSuffix // // Since this method allows integer-only strings as input // in addition to strings of floating-point literals, the // two sub-patterns below are simplifications of the grammar // productions from section 3.10.2 of // The Java™ Language Specification. // Digits ._opt Digits_opt ExponentPart_opt FloatTypeSuffix_opt "((("+Digits+"(\\.)?("+Digits+"?)("+Exp+")?)|"+ // . Digits ExponentPart_opt FloatTypeSuffix_opt "(\\.("+Digits+")("+Exp+")?)|"+ // Hexadecimal strings "((" + // 0[xX] HexDigits ._opt BinaryExponent FloatTypeSuffix_opt "(0[xX]" + HexDigits + "(\\.)?)|" + // 0[xX] HexDigits_opt . HexDigits BinaryExponent FloatTypeSuffix_opt "(0[xX]" + HexDigits + "?(\\.)" + HexDigits + ")" + ")[pP][+-]?" + Digits + "))" + "[fFdD]?))" + "[\\x00-\\x20]*");// Optional trailing "whitespace" if (Pattern.matches(fpRegex, myString)) Double.valueOf(myString); // Will not throw NumberFormatException else { // Perform suitable alternative action
}
Upvotes: 1
Reputation: 1780
It's nice to try a regex before using it, this website is quite visual: https://www.debuggex.com/
I think you should go with: ^[0-9]+(.|,)?[0-9]?$
That said, neminem and Johnsyweb are right, you don't have to use a regex for this.
Upvotes: 3
Reputation: 51
Using Regex
I tested and confirmed the following is working:
^\\d+(\\.\\d+)?
Upvotes: 1
Reputation: 2182
This should do:
"^[0-9]+([,.][0-9]?)?$"
Edit: I removed the slashes. I see flaws in all other patterns posted here. You dont need to escape characters inside [] - except for ] . The question did not restrict the number of digits before the decimal separator. But it allowed for only one after the decimal.
Upvotes: 3
Reputation:
Could get you started -
edited out delimiters
# "^(?:[1-9]\\d{0,2}(?:,\\d{3})*(?:[.]\\d*)?|\\d+[.]?\\d*)$"
^
(?:
[1-9]
\d{0,2}
(?:
, \d{3}
)*
(?:
[.] \d*
)?
|
\d+ [.]? \d*
)
$
Identical, but more compact formatting -
^
(?:
[1-9] \d{0,2}
(?: , \d{3} )*
(?: [.] \d* )?
|
\d+ [.]? \d*
)
$
Upvotes: 1
Reputation: 175
I must get using try, catches again..
try
{
double doubleHeight = Double.parseDouble(height);
DecimalFormat df = new DecimalFormat("#.00");
String decHeight = df.format(doubleHeight);
if(decHeight.charAt(0)=='.')
{
decHeight = "0" + decHeight;
}
}
catch(NumberFormatException e)
{
isHeightValid = false;
}
Upvotes: 1
Reputation: 6276
The regex you need is this one:
^[0-9]+([\\,\\.][0-9]+)?$
Tested it, it works.
Upvotes: 1
Reputation: 31699
Do you really need the input string to contain slashes (/
characters)? If not, remove them from your regular expression. Perl and JavaScript use slash characters to denote a "regular expression literal", which is something built into those languages for pattern matching. Java doesn't have regular expression literals; regex patterns are created from ordinary string literals. Thus the slashes aren't used, and if you put one in a regex it assumes you really want to match a slash.
Upvotes: 1
Reputation: 176
Just want to point out that using regex could have some flaws, such as
accepting these: 0,
00,0
but not accepting 1,000.00
A good regex is hard to write.
For a simple case like this, using Double.parseDouble() and a try-catch block as others mentioned would be more suitable.
Upvotes: 3
Reputation: 2642
Any reason why you're using a regex? You could try using Double.parseDouble() from http://docs.oracle.com/javase/7/docs/api/java/lang/Double.html#parseDouble(java.lang.String
And then catch the NumberFormatException if the format is not correct to handle that user input error in your own way.
EDIT: I didn't read all of your code to begin with. You can get rid of the first if statement and do a try-catch on Double.parseDouble(height)
if it reaches the catch block you know it did not succeed.
Upvotes: 2