Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Bash RegEx to check floating point numbers from user input

I'm relatively new to bash programming and i am currently creating a simple calculator.

It needs to use floating point numbers and check they are so.

I have a checkNumbers function:

function checkNumber {

    regExp=[0-9]

    if [ $testNo =~ $regExp ]
    then
        echo "That is a number!"
        let check=1
    else
        echo "Damn! Not A Number!"
    fi
}

where i get the user to input a number like this:

while [ $check -eq 0]
do
    echo "Please enter a number
    read testNo
    echo ""
    checkNumber
done

This does not work, i get this error:

./calculator.sh: line 39: [: =~: binary operator expected

line 39 is:

if [ $testNo =~ $regExp ] 

I have tried lots of Regular Expressions like:

^*[0-9]*$

and

^*[0-9]\.[0.9]*$

etc etc.

also, i have tied other ways of performing the check:

case $testNo
in
    ^*[0-9]*$) echo "That is a number!";;
    *) echo "Error! Not a number!";;
esac

and

if [ $testNo = ^*[0-9]*$ ]
then
    echo "etc etc"
else
    echo "oops"
fi

I also need this to work with floating point numbers.

could someone please let me know how i go about this?

like image 410
Sam_Web Avatar asked Dec 09 '12 19:12

Sam_Web


People also ask

What =~ in bash?

A regular expression matching sign, the =~ operator, is used to identify regular expressions. Perl has a similar operator for regular expression corresponding, which stimulated this operator.

How do you check if a string matches a regex in bash?

You can use the test construct, [[ ]] , along with the regular expression match operator, =~ , to check if a string matches a regex pattern (documentation). where commands after && are executed if the test is successful, and commands after || are executed if the test is unsuccessful.

What is the expression to represent floating point number?

[0-9]*. This defines a floating point number as an optional sign, followed by an optional series of digits (integer part), followed by an optional dot, followed by another optional series of digits (fraction part).

How do you use numbers in regular expressions?

To match any number from 0 to 9 we use \d in regex. It will match any single digit number from 0 to 9. \d means [0-9] or match any number from 0 to 9. Instead of writing 0123456789 the shorthand version is [0-9] where [] is used for character range.


2 Answers

This regex ^[-+]?[0-9]+\.?[0-9]*$ will match only digits with an optional .:

$ echo 30 | grep -Eq '^[-+]?[0-9]+\.?[0-9]*$' && echo Match
Match

$ echo 30.10 | grep -Eq '^[-+]?[0-9]+\.?[0-9]*$' && echo Match
Match

$ echo 30. | grep -Eq '^[-+]?[0-9]+\.?[0-9]*$' && echo Match
Match

$ echo +30 | grep -Eq '^[-+]?[0-9]+\.?[0-9]*$' && echo Match
Match

$ echo -30 | grep -Eq '^[-+]?[0-9]+\.?[0-9]*$' && echo Match
Match

I think when you tried ^*[0-9] you wanted ^[0-9]*

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

Note: this matches numbers followed by a . like 30., not sure if this is acceptable for you.

Edit: Don't quote the regex

testNo=30.00

if [[ $testNo =~ ^[+-]?[0-9]+\.?[0-9]*$ ]]; then 
    echo Match
fi

>>> Match
like image 90
Chris Seymour Avatar answered Nov 09 '22 21:11

Chris Seymour


To use that type of feature, you need the [[ ... ]] version of the conditional. [ is the "old" test command and doesn't handle regular expressions at all.

#! /bin/bash
function checkNumber {
    regExp='^[+-]?([0-9]+\.?|[0-9]*\.[0-9]+)$'
    if [[ $testNo =~ $regExp ]]
    then
        echo "That is a number!"
        let check=1
    else
        echo "Damn! Not A Number!"
    fi
}
testNo=1
checkNumber
testNo=-1.2
checkNumber
testNo=+.2
checkNumber
testNo=+0.
checkNumber
testNo=a
checkNumber
testNo=hello2you
checkNumber

$ ./t.sh
That is a number!
That is a number!
That is a number!
That is a number!
Damn! Not A Number!
Damn! Not A Number!

See What is the difference between test, [ and [[ ?.

An explanation on the regex:

^ Anchor at start of string
$ Anchor at end of string

These two make the regex match the whole string passed, partial matches are not allowed.

[+-]

matches either + or -.

[+-]?

makes that part optional, so the above matches exactly +, - or nothing at all.

Then there's an alternation (part1|part2) which will match if part1 or part2 matches.

Part one is:

[0-9]+\.?

which matches one or more (+) digits (but not zero digits/empty set) and an optional .. This handles numbers of the form 123 and 534.. But not just ..

Part two is:

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

This matches zero or more (*) digits, followed by a ., followed by one or more digits. This matches all other floats like 1.3 or .543 (without exponent notation), but still excludes just ..

like image 3
Mat Avatar answered Nov 09 '22 20:11

Mat