user3211740
user3211740

Reputation: 175

Regex to find int or double

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

Answers (12)

bluelhf
bluelhf

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

zim1992
zim1992

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

sesquipedalias
sesquipedalias

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

Arnaud Potier
Arnaud Potier

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

navin shah
navin shah

Reputation: 51

Using Regex I tested and confirmed the following is working:

^\\d+(\\.\\d+)?

Upvotes: 1

SebastianH
SebastianH

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

user557597
user557597

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

user3211740
user3211740

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

Dakkaron
Dakkaron

Reputation: 6276

The regex you need is this one:

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

Tested it, it works.

Upvotes: 1

ajb
ajb

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

ptantiku
ptantiku

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

Lucas
Lucas

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

Related Questions