8

I've never used regex before, but this java function requires it (shown here: How to set Edittext view allow only two numeric values and two decimal values like ##.##)

I basically just need to get a float from it the text box, should be simple. I used a tool and it said this should work:

String re1="([+-]?\\d*\\.\\d+)(?![-+0-9\\.])";

But it doesn't seem to be working, it doesn't let me put anything in the text box.

What's the right way to do this? Thanks

kapex
  • 28,903
  • 6
  • 107
  • 121
Jdban101
  • 367
  • 1
  • 3
  • 21

6 Answers6

11

Try this:

String re1="^([+-]?\\d*\\.?\\d*)$";
Paul
  • 139,544
  • 27
  • 275
  • 264
  • Hmm, for some reason whenever I type a decimal it does a backspace... so 1234.5 turns into 1235. I assume this isn't the regex's fault, so thank you :) – Jdban101 Jul 19 '11 at 21:58
  • That is the regexes fault, sorry. Let me fix it. – Paul Jul 19 '11 at 22:15
  • I had it not allowing a string like `2.` with nothing after the dot since that would normally be written as `2.0`, but then it never let's you get to `2.0`, so I changed it to allow `2.` now. – Paul Jul 19 '11 at 22:17
  • AAAAnd, I just noticed that it won't let me enter ".5" without the "0" in front of it. – Jdban101 Jul 19 '11 at 22:48
  • Helped a lot with trying to filter a string parameter before conversation to float. This saved me some headache, especially since I am still sort of new to Java (coming from PHP, there is reason). Thanks for the answer. :) – Scrydan Apr 10 '15 at 11:47
  • 4
    This matches the empty string, or a single dot, or a plus or a minus by itself. – Christoffer Hammarström Sep 01 '16 at 08:40
8

The right way for this problem isn't to use a regex, but just to use:

try {
     Float.parseFloat(string)
     return true;
}
catch (NumberFormatException ex) {
     return false;
}

Works perfectly fine, is the same code that is later used to parse the float and therefore bug free (or if it isn't we have a much bigger problem at hand).

Voo
  • 29,040
  • 11
  • 82
  • 156
  • I'd prefer that it not allow people to enter in letters, which is why I prefer the regex solution. I may end up doing it your way though, which was my initial plan. – Jdban101 Jul 19 '11 at 22:01
  • And why would Float.parseFloat() allow letters to go through as a float? It's not as if 1.f3 was a valid float to begin with. Also in this case you can make additional checks like making sure the parsed Float is usable. Presumably Float.INFINITY shouldn't be allowed, although both the regex and parseFloat will let it through as valid float - but in the parseFloat case you can check for it. – Voo Jul 19 '11 at 22:02
  • I know that this will tell me if the value in the box is a float or not, but I want the value in the box to NEVER not be a float (if that mkaes any sense) – Jdban101 Jul 19 '11 at 22:05
  • @Jdban101: That's a separate problem. You need to see whether or not it's a float first. If it isn't a float, blank out the textbox or something. – Platinum Azure Jul 19 '11 at 22:44
  • @Jdban101: While I'm not certain that's a good idea (it's not usual and results in strange behavior without the chance to show a good error message - that's bad GUI design) - that doesn't change the problem. If you want to do this you have to check after each keystroke if the float is valid - HOW you do that is unimportant for that. – Voo Jul 19 '11 at 23:43
  • This worked well for me, but just to add, I used a string to return a flag for me to check against. String carryon = "true" unless catch, then carryon = "false" Thanks for this! It helped me move fwd. – jasonflaherty Jul 11 '15 at 05:11
  • If EditText can execute a user defined callback (delegate?) to perform the validation then doing what you prescribe in your answer would be far superior to a re based solution. But when I read the javadoc, I don't see that capability. – Jeff Holt Aug 23 '18 at 21:44
  • 1
    @jeff Any GUI framework that ever was needs some kind of property changed event handler. Android's edittext has TextView.addTextChangedListener(TextWatcher). – Voo Aug 23 '18 at 23:42
  • In that case, your solution should be the one that was accepted. Other than completeness, my tests indicate your solution finishes in 1/7th the time of using regex + parseFloat and it doesn't require as much garbage collection. – Jeff Holt Aug 23 '18 at 23:49
5

After balking at the accepted answer (and the other two relevant ones), I decided to provide a new one. Then I found Christoffer Hammarström's Sep 1 '16 at 8:40 mostly hidden comment on Paulpro's answer (which was accepted).

Here's the accepted answer:

String re1="^([+-]?\d*\.?\d*)$";

Here's Christoffer's comment:

This matches the empty string, or a single dot, or a plus or a minus by itself.

In fact, none of the 3 answers that adhere to the requirement of the OP do a good job, which is that he must provide an RE to some other class object and allow an end user to type in any valid floating point number.

Here is my case for a new answer.

In summary, my answer is [+-]?(\d+|\d+\.\d+|\.\d+|\d+\.)([eE]\d+)?. You must add ^ at the beginning and $ at the end the expression if the class object might otherwise give a pass to invalid leading or trailing characters.

Here's how I read the expression as written above:

[+-]?

This means a leading sign character is allowed but not required.

( \d+ | \d+\.\d+ | \.\d+ | \d+\. )

I've added whitespace to make it easier to see what's going on. This means accept the 4 forms of commonly accepted expressions of signless non-scientific-notation floating point numbers. Many computer languages allow for all four. Perhaps with more grouping, this part of the expression could be compressed but at the expense of readability.

([eE]\d+)?

This final part means a scientific notation suffix is allowed by not required.

Here's all the code.

$ cat Tester.java | sed 's/^/    /'

import java.util.*;
import java.util.regex.*;

public class Tester {

    private class TestVal {
        private String  val;
        private boolean accepted;
        private boolean expect;
        private boolean tested;
        public TestVal (String testValue, boolean expectedResult) {
            val = testValue;
            expect = expectedResult;
            reset();
        }
        public String   getValue    () { return val; }
        public boolean  getExpect   () { return expect; }
        public void     reset       () { tested = false; accepted = false; }
        public boolean  getAccepted () { return accepted; }
        public boolean  getTested   () { return tested; }
        public void     setAccepted (boolean newAccept) { tested = true; accepted = newAccept; }
    }

    private ArrayList<TestVal> tests = new ArrayList<TestVal>();

    public void doRETest (Pattern re, TestVal tv) {
            boolean matches = re.matcher(tv.getValue()).matches();
            boolean ok = matches == tv.getExpect();
            String result = ok ? "success" : "fail";
            System.out.println(String.format("%10s matches=%5s: %s", tv.getValue(), matches, result));
            tv.setAccepted(ok);
    }

    private void testsSummary () {
        int skipped = 0;
        int passes = 0;
        int failures = 0;
        for (TestVal tv : tests)
            if (tv.getTested())
                if (tv.getAccepted())
                    passes++;
                else
                    failures++;
            else
                skipped++;
        System.out.println(String.format("\npassed %d tests, failed %d tests, and %d tests skipped\n\n", passes, failures, skipped));
    }

    public void doRETests (String re) {
        Pattern p = Pattern.compile(re);
        System.out.println(String.format("testing %s", re));
        for (TestVal tv : tests) {
            tv.reset();
            doRETest(p, tv);
        }
        testsSummary();
    }

    public Tester () {
        tests.add(new TestVal("1", true));
        tests.add(new TestVal(".1", true));
        tests.add(new TestVal("1.", true));
        tests.add(new TestVal("1.0", true));

        tests.add(new TestVal("+1", true));
        tests.add(new TestVal("+.1", true));
        tests.add(new TestVal("+1.", true));
        tests.add(new TestVal("+1.0", true));

        tests.add(new TestVal("-1", true));
        tests.add(new TestVal("-.1", true));
        tests.add(new TestVal("-1.", true));
        tests.add(new TestVal("-1.0", true));

        tests.add(new TestVal("1e2", true));
        tests.add(new TestVal(".1e2", true));
        tests.add(new TestVal("1.e2", true));
        tests.add(new TestVal("1.0e2", true));

        tests.add(new TestVal("1.0e2.3", false));
        tests.add(new TestVal(".", false));
        tests.add(new TestVal("", false));
        tests.add(new TestVal("+", false));
        tests.add(new TestVal("-", false));
        tests.add(new TestVal("a", false));
    }

    public static void main (String args[]) {
        Tester t = new Tester();

        String paulpro  = "^([+-]?\\d*\\.?\\d*)$";
        String lucac    = "^([+-]?(\\d+\\.)?\\d+)$";
        String armaj    = "\\d+\\.\\d+";
        String j6t7     = "[+-]?(\\d+|\\d+\\.\\d+|\\.\\d+|\\d+\\.)([eE]\\d+)?";

        t.doRETests(paulpro);
        t.doRETests(lucac);
        t.doRETests(armaj);
        t.doRETests(j6t7);

    }

}

And here's what happened when I executed it.

$ javac Tester.java && java Tester | sed 's/^/    /'

testing ^([+-]?\d*\.?\d*)$
         1 matches= true: success
        .1 matches= true: success
        1. matches= true: success
       1.0 matches= true: success
        +1 matches= true: success
       +.1 matches= true: success
       +1. matches= true: success
      +1.0 matches= true: success
        -1 matches= true: success
       -.1 matches= true: success
       -1. matches= true: success
      -1.0 matches= true: success
       1e2 matches=false: fail
      .1e2 matches=false: fail
      1.e2 matches=false: fail
     1.0e2 matches=false: fail
   1.0e2.3 matches=false: success
         . matches= true: fail
           matches= true: fail
         + matches= true: fail
         - matches= true: fail
         a matches=false: success

passed 14 tests, failed 8 tests, and 0 tests skipped


testing ^([+-]?(\d+\.)?\d+)$
         1 matches= true: success
        .1 matches=false: fail
        1. matches=false: fail
       1.0 matches= true: success
        +1 matches= true: success
       +.1 matches=false: fail
       +1. matches=false: fail
      +1.0 matches= true: success
        -1 matches= true: success
       -.1 matches=false: fail
       -1. matches=false: fail
      -1.0 matches= true: success
       1e2 matches=false: fail
      .1e2 matches=false: fail
      1.e2 matches=false: fail
     1.0e2 matches=false: fail
   1.0e2.3 matches=false: success
         . matches=false: success
           matches=false: success
         + matches=false: success
         - matches=false: success
         a matches=false: success

passed 12 tests, failed 10 tests, and 0 tests skipped


testing \d+\.\d+
         1 matches=false: fail
        .1 matches=false: fail
        1. matches=false: fail
       1.0 matches= true: success
        +1 matches=false: fail
       +.1 matches=false: fail
       +1. matches=false: fail
      +1.0 matches=false: fail
        -1 matches=false: fail
       -.1 matches=false: fail
       -1. matches=false: fail
      -1.0 matches=false: fail
       1e2 matches=false: fail
      .1e2 matches=false: fail
      1.e2 matches=false: fail
     1.0e2 matches=false: fail
   1.0e2.3 matches=false: success
         . matches=false: success
           matches=false: success
         + matches=false: success
         - matches=false: success
         a matches=false: success

passed 7 tests, failed 15 tests, and 0 tests skipped


testing [+-]?(\d+|\d+\.\d+|\.\d+|\d+\.)([eE]\d+)?
         1 matches= true: success
        .1 matches= true: success
        1. matches= true: success
       1.0 matches= true: success
        +1 matches= true: success
       +.1 matches= true: success
       +1. matches= true: success
      +1.0 matches= true: success
        -1 matches= true: success
       -.1 matches= true: success
       -1. matches= true: success
      -1.0 matches= true: success
       1e2 matches= true: success
      .1e2 matches= true: success
      1.e2 matches= true: success
     1.0e2 matches= true: success
   1.0e2.3 matches=false: success
         . matches=false: success
           matches=false: success
         + matches=false: success
         - matches=false: success
         a matches=false: success

passed 22 tests, failed 0 tests, and 0 tests skipped
Jeff Holt
  • 2,940
  • 3
  • 22
  • 29
4

This is the correct way:

String floatRegexp="^([+-]?(\\d+\\.)?\\d+)$";

or if you look also in the middle of other text:

String floatRegexp="([+-]?(\\d+\\.)?\\d+)";

and if you don't look for the minus/plus sign:

String floatRegexp="^(\\d+\\.)?\\d+$";
Luca C.
  • 11,714
  • 1
  • 86
  • 77
0

this answer is from Johan Sjöberg https://stackoverflow.com/a/12235002/4035655

You could try matching the digits using a regular expression

\\d+\\.\\d+

This could look something like

Pattern p = Pattern.compile("\\d+\\.\\d+");
Matcher m = p.matcher("Sstring>26.0.[2.3.2.3D] .352.(f) 1)"503B"(\1.67>>Sstring");
while (m.find()) {
    System.out.println(Float.parseFloat(m.group()));
}

the output is:

26.0
2.3
2.4
1.67

the part [2.3.2.3D] of the string is split into two separate float numbers

Ar maj
  • 1,974
  • 1
  • 16
  • 16
0
String floatRegex = "[+-]?\\d*([.]?\\d+)";
N Djel Okoye
  • 950
  • 12
  • 10