3

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

ajb
  • 31,309
  • 3
  • 58
  • 84
user3211740
  • 175
  • 3
  • 6
  • 12
  • Why would you use a regex for this? – johnsyweb Jan 27 '14 at 17:35
  • 5
    Why would you want to use a regex? That's not really what it's for. If you want to see whether a string is an int, use a built-in int parsing function. If you want to see whether it's a double, use a double-parsing function. Put down the chocolate-covered banana and step away from the European currency systems. [See also.](http://homepage.ntlworld.com/jonathan.deboynepollard/FGA/put-down-the-chocolate-covered-banana.html) (Edit: I misread this as being C#, durp. Comment still holds, though, just not the names of the functions.) – neminem Jan 27 '14 at 17:36
  • Also, of possible helpfulness: http://stackoverflow.com/questions/8391979/does-java-have-a-int-tryparse-that-doesnt-throw-an-exception-for-bad-data – neminem Jan 27 '14 at 17:42
  • Regex is a perfect choice to validate numeric input. –  Jan 27 '14 at 18:49
  • Note to everyone who suggests using a built-in parsing function instead of a regex: The OP's regex suggests that he wants to allow comma characters in the input, which the built-in parsing functions don't allow. – ajb Jan 27 '14 at 18:57

12 Answers12

3

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.

SebastianH
  • 2,172
  • 1
  • 18
  • 29
3

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.

Kevin Panko
  • 8,356
  • 19
  • 50
  • 61
Arnaud Potier
  • 1,750
  • 16
  • 28
3

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.

ptantiku
  • 76
  • 2
  • 2
    Note that `Double.parseDouble()` won't accept `"1,000.00"` either. That's a flaw with everyone's answer that suggests using one of those parsing functions instead of a regex. It doesn't allow for possible formats that the OP might want to accept but the built-in parsing functions don't (such as input with commas in it). – ajb Jan 27 '14 at 18:57
2

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.

Lucas
  • 2,514
  • 4
  • 27
  • 37
1

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;             
        }
user3211740
  • 175
  • 3
  • 6
  • 12
  • 1
    I'd put the `try`..`catch` around *only* the first statement. Or change the `catch` to catch only `NumberFormatException`, instead of all `Exception`s. The way you've written it, if there's a bug in the rest of your code and something goes wrong, the method will report (incorrectly) that the input was invalid, rather than dumping a stack trace that would help you figure out where your code is wrong. – ajb Jan 27 '14 at 18:05
1

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.

ajb
  • 31,309
  • 3
  • 58
  • 84
1

The regex you need is this one:

^[0-9]+([\\,\\.][0-9]+)?$

Tested it, it works.

Dakkaron
  • 5,930
  • 2
  • 36
  • 51
1

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* 
 )
 $
1

Using Regex I tested and confirmed the following is working:

^\\d+(\\.\\d+)?
ivcubr
  • 1,988
  • 9
  • 20
  • 28
navin shah
  • 51
  • 3
1

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

}

sesquipedalias
  • 183
  • 2
  • 10
1

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));
    }
}
bluelhf
  • 71
  • 1
  • 7
0

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");
                })

zim1992
  • 1
  • 2