只允许浮点正则表达式

只允许浮点正则表达式

如何检查特定字符串是否为浮点数?这是可能的浮点:

12.245
+.0009
3.11e33
43.1E11
2e-14

这是我尝试过的:

grep "^[+\-\.0-9]" 
grep "^[+-]*[0-9]"
grep "^[+\-\.0-9]" 

还有其他很多相关的东西,但根本没有过滤任何东西。几乎每根弦都穿过了。我该如何解决这个问题?

答案1

grep -xE '[-+]?[0123456789]*\.?[0123456789]+([eE][-+]?[0123456789]+)?'

使用-x,我们将正则表达式锚定在行的开头和位置,因此行必须与整个模式匹配,而不是在行中的任何位置找到模式。

如果您想匹配所有支持的POSIX/Cstrtod()正如该实用程序的许多实现所认可的那样,printf例如:

r=[$(locale decimal_point)]
d=[0123456789]
h=[0123456789abcdefABCDEF]
grep -xE "[[:space:]]*[-+]?($d*$r?$d+([eE][-+]?$d+)?|\
0[xX]$h*$r?$h*([pP][-+]?$d+)?|\
[iI][nN][fF]([iI][nN][iI][tT][yY])?|\
[nN][aA][nN]|\
NAN\([abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_]+\))"

因此还包括 0x3f、0xFP-4、-Infinity、NAN(无论什么)之类的东西。

$ printf '%g\n' 0x3f 0xFp-4 -Infinity 'NAN(whatever)'
63
0.9375
-inf
nan

答案2

选择Python解决方案(对于较少的复杂的输入项):

样本input.txt文件:

11
12.245
+.0009
---0
3.11e33
43.1E11
2e-14
t12
aaa
10.001

check_float.py脚本:

import sys

with open(sys.argv[1], 'r') as inp:
    f = 'No'
    for l in inp.read().splitlines():
        try:
            if float(l) and '.' in l: f = 'Yes'
        except ValueError:
            f = 'No'
        finally:
            print '{0} - {1}'.format(l, f)

用法:

python check_float.py input.txt

输出:

11 - No
12.245 - Yes
+.0009 - Yes
---0 - No
3.11e33 - Yes
43.1E11 - Yes
2e-14 - Yes
t12 - No
aaa - No
10.001 - Yes

答案3

免责声明:这是一个不完美的解决方案。 Perl 的Scalar::Util::looks_like_number()函数可能不是执行此操作的最佳例程选择。看StéphaneChazelas 评论如下

如果有人想看它并coproc从中挑选一些内容,我就把它留在这里。


不要尝试编写自己的正则表达式来匹配许多可能的浮点数格式,而是使用已经实现它的库:

perl -MScalar::Util -ne 'exit !Scalar::Util::looks_like_number($_)'

作为bash外壳函数:

is_number () {
    perl -MScalar::Util -ne 'exit !Scalar::Util::looks_like_number($_)' <<<"$1"
}

is_number hello && echo 'hello is a number'
is_number 1.234 && echo '1.234 is a number'

作为bash协同进程(以避免每次想要测试数字时都启动 Perl 进程):

coproc PERLIO=:raw perl -MScalar::Util -ne \
    'print Scalar::Util::looks_like_number($_) ? "Yes" : "No", "\n"'

while IFS= read -r -p 'Number please: ' possnum; do
    printf '%s\n' "$possnum" >&${COPROC[1]}
    read -u ${COPROC[0]}

    case "$REPLY" in
        Yes)    printf '%s is a number\n' "$possnum"       ;;
        No)     printf '%s is _not_ a number\n' "$possnum" ;;
    esac
done

kill "$COPROC_PID"

或者将两者结合起来:

coproc PERLIO=:raw perl -MScalar::Util -ne \
    'print Scalar::Util::looks_like_number($_) ? "Yes" : "No", "\n"'

is_number () {
    printf '%s\n' "$1" >&${COPROC[1]}

    local REPLY
    read -u ${COPROC[0]}

    [ "$REPLY" = 'Yes' ] && return 0

    return 1
}

while IFS= read -r -p 'Number please: ' possnum; do
    if is_number "$possnum"; then
        printf '%s is a number\n' "$possnum"
    else
        printf '%s is a _not_ a number\n' "$possnum"
    fi
done

kill "$COPROC_PID"

相关内容