1

I'm using a regular expression to match floating point numbers:

for f in $float_numbers ; do
    if [ $f =~ "[0-9]*\.?[0-9]*" ] ; then
        echo "****f is $f ****"
    fi
done

where $float_numbers contains floating point numbers like 1.2, 10.5, 4.0, etc.

But nothing matches.

1
  • When asking a question, you should also include the error messages you are getting.
    – terdon
    Commented Dec 5, 2016 at 10:20

4 Answers 4

1

terdon has corrected your syntax, but your regular expression is wrong:

[0-9]*\.?[0-9]*

All quantifiers there (*, ?) mean all parts of the expression are optional. That means your regex will match every string, including strings that are empty and strings that have no digits.

To match a float number, you need to match at least one digit.

([0-9]+\.?[0-9]*)|([0-9]*\.[0-9]+)

That matches some digits with an optional decimal point and optional digits (example: 3.14 or 42), or some optional digits but a required decimal point and required digits (example: .1234 or 3.14).

It is not anchored, so the string "PI starts with 3.14 and continues" will match.

Testing:

for n in "" "no digits" 42 3.14 "this is .1234 go"; do 
    if [[ $n =~ ([0-9]+\.?[0-9]*)|([0-9]*\.[0-9]+) ]]; then
        echo "yes -- $n -- ${BASH_REMATCH[0]}"
    fi
done
yes -- 42 -- 42
yes -- 3.14 -- 3.14
yes -- this is .1234 go -- .1234
0
1

First of all, your code has a syntax error and should complain about:

bash: [: =~: binary operator expected

Assuming you are running bash, but based on your code, you probably are. So, in bash, the =~ only works inside [[ ]], not [ ]. You also shouldn't quote your regular expression. You are looking for something like this:

$ for f in $float_numbers; do 
    [[ $f =~ [0-9]*\.?[0-9]* ]] && echo $f
  done
1.2
10.5
4.0

However, as Glenn very correctly pointed out, your regex is wrong in the first place.

0

I suggest you to use this txt2re to build regex that match what you want.

For you script:

for f in $float_numbers ; do
    if [[ $f =~ ^[+-]?[0-9]+\.?[0-9]*$ ]]; then
        echo "****f is $f ****"
    fi
done

Rexeplanation:

^       # Match start of string
[-+]?   # Match a leading + or - (optional)
[0-9]+  # Match one or more digit
\.?     # Match a literal . (optional, escaped)
[0-9]*  # Match zero or more digits
$       # Match the end of the string

And this is perl script generated by the previous site that match a float numbers

#!/usr/bin/perl

# URL that generated this code:
# http://txt2re.com/index.php3?s=100.3&1

$txt='100.3';

$re1='([+-]?\\d*\\.\\d+)';  # Float 1

$re=$re1;
if ($txt =~ m/$re/is)
{
    $float1=$1;
    print "($float1) \n";
}

#-----
# Paste the code into a new perl file. Then in Unix:
# $ perl x.pl 
#-----
2
  • Why would you use \\d* instead of \d? Why are you using a negative lookahead there? You are matching "1 or more digits" (\d+) and "not followed by =,-, . or more digits. I dont' understand why that helps in any way.
    – terdon
    Commented Dec 5, 2016 at 10:19
  • @terdon i totally agree with you i didn't find any reason to (?![-+0-9\\.]) Commented Dec 5, 2016 at 10:34
0

A more precise regular expression for matching floats would be:

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

This comes down to what you would consider a float. Python, for example, accepts both 5. and .5 as valid floats, and does not require a leading or trailing digit before or after the .:

>>> 5.
5.0
>>> .5
0.5

So the above regex handles these cases, and also the edge case of just . (which should not be a match).

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .