用正则表达式匹配浮点数

来源:流泪鱼评论12,931

在这个例子中,我将向你展示如何避免不熟悉正则表达式的人常犯的一些错误。我们将尝试建立一个可以匹配浮点数的正则表达式。我们的正则表达式也应该匹配整数,以及整数部分(即0)没有给出来的浮点数。

乍看之下,下面的正则表达式似乎可以达到预期效果[-+]?[0-9]*\.?[0-9]*。这定义了一个这样的浮点数:可选的符号(正负号),接着是可选的一连串数字(整数部分),接着是可选的点号(小数点),再接着是可选的一连串数字(小数部分)。

用单词拼出这个正则表达式使之更加明显:正则表达式中所有的部分都是可选的。这个正则表达式会把一个符号(正负号)或者一个点号(小数点)当成有效的浮点数。事实上,它会把一个空字符串当成有效的浮点数。如果它被用于像 Perl 或者 PHP 一样的脚本语言来验证用户输入,这个正则表达式将会引起严重的麻烦。

不转义点号也是一个常见的错误。一个没有转义的点号将匹配任何字符,包括点号。如果我们没有转义点号,4.4将被认为是浮点数,4X4也一样。

创建正则表达式时,更重要的是考虑它不应该相配的,而不是它应该匹配的。因为正则表达式引擎是贪婪的,所以上述正则表达式的确可以匹配一个正确的浮点数。但是它也将会相配许多我们不想要,我们必须排除。

在这里有一个更好的尝试:[-+]?([0-9]*\.[0-9]+|[0-9]+)。这个正则表达式将会匹配一个可选的符号(正负号),或者紧接着零个或更多的数字紧接着一个点号(小数点)再紧接着一个或更多的数字(一个整数部分可选的浮点数),或者紧接着一个或更多的数字(整数)。

这是一种更好的定义,所有的匹配都至少包含一个数字,因为[0-9]+ 部分的关系。我们成功的排除了我们不想要的匹配:那些不包含数字的。

我们可以把正则表达式优化成:[-+]?[0-9]*\.?[0-9]+

最后,如果你是想验证一个字符串是否为浮点数,而不是在一个长字符串中查找浮点数,你必须在正则表达式中使用锚点:^[-+]?[0-9]*\.?[0-9]+$

发表评论

匿名网友