提问者:小点点

浮点数的正则表达式


我的任务是匹配浮点数。我为它编写了以下正则表达式:

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

但是,它返回一个错误:

Invalid escape sequence (valid ones are  \b  \t  \n  \f  \r  \"  \'  \\ )

据我所知,我们需要为使用转义字符也是。请纠正我哪里错了。


共3个答案

匿名用户

使用[.]而不是\.[0-9]而不是\d来避免某些语言中的转义问题(如Java)。

感谢无名者最初认识到这一点

在较大字符串中匹配浮点数的一种相对简单的模式是:

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

这将匹配:

  • 123
  • 123.456
  • .456

查看一个工作示例

如果您还想匹配123(不含小数部分的句点),则需要稍长的表达式:

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

有关此模式的更全面解释,请参见pkeller的答案

如果您想包括更广泛的数字,包括科学记数法和非十进制数字,如十六进制和八进制,请参阅我对如何识别字符串是否为数字的回答?。

如果要验证输入是否为数字(而不是在输入中查找数字),则应使用^$围绕模式,如下所示:

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

在大多数现代语言、API、框架、库等中实现的“正则表达式”都基于形式语言理论中发展的概念。然而,软件工程师添加了许多扩展,使这些实现远远超出了正式定义。因此,尽管大多数正则表达式引擎彼此相似,但实际上并没有标准。因此,很大程度上取决于您使用的语言、API、框架或库。

(顺便说一句,为了帮助减少混淆,许多人开始使用“regex”或“regexp”来描述这些增强的匹配语言。有关更多信息,请参阅Rexeg.com上的regex是否与正则表达式相同。)

也就是说,大多数正则表达式引擎(事实上,据我所知,所有的正则表达式引擎)都会接受\。很可能是逃跑的问题。

有些语言内置了对正则表达式的支持,比如JavaScript。对于那些不这样做的语言来说,逃跑可能是个问题。

这是因为您基本上是在一种语言中使用一种语言进行编码。例如,Java在其字符串中使用\作为转义字符,因此如果要在字符串中放置文字反斜杠字符,必须转义:

// creates a single character string: "\"
String x = "\\";

但是,正则表达式也使用\字符进行转义,因此如果要匹配文本\字符,则必须对正则表达式引擎进行转义,然后对Java再次进行转义:

// Creates a two-character string: "\\"
// When used as a regex pattern, will match a single character: "\"
String regexPattern = "\\\\";

在您的情况下,您可能没有在编程语言中转义反斜杠字符:

// will most likely result in an "Illegal escape character" error
String wrongPattern = "\.";
// will result in the string "\."
String correctPattern = "\\.";

所有这些逃跑会变得非常混乱。如果您使用的语言支持原始字符串,那么您应该使用这些字符串来减少反斜杠的数量,但并不是所有语言都支持反斜杠(最值得注意的是:Java)。幸运的是,有一个替代方案在某些时候会奏效:

String correctPattern = "[.]";

对于正则表达式引擎,\[.]意思完全相同。请注意,这并不适用于所有情况,如换行符(\\n)、方括号(\\[)和反斜杠(\\\\\[\\])。

(提示:这比你想象的要难)

匹配一个数字是你认为用正则表达式很容易的事情之一,但实际上很棘手。让我们来看看你的方法,一块一块地:

[-+]?

匹配可选的-

[0-9]*

匹配0个或多个连续数字

\.?

匹配一个可选的.

[0-9]*

匹配0个或多个连续数字

首先,我们可以通过对数字使用字符类速记来稍微清理这个表达式(注意,这也容易受到上述转义问题的影响):

[0-9]=\d

我将在下面使用\d,但请记住,它的意思与[0-9]相同。(实际上,在某些引擎中,\d将匹配所有脚本中的数字,所以它将比[0-9]匹配更多,但这在您的情况下可能并不重要。)

现在,如果你仔细看看这个,你会意识到你的模式的每一个部分都是可选的。此模式可以匹配长度为0的字符串;仅由-组成的字符串;或者,仅由组成的字符串。。这可能不是你的本意。

要解决这一问题,最好先用最小的字符串(可能是一个位数)来“锚定”正则表达式:

\d+

现在我们想添加小数部分,但它没有达到您认为可能的程度:

\d+\.?\d* /* This isn't quite correct. */

这仍然会匹配像123这样的值。更糟糕的是,它有一点邪恶。句点是可选的,这意味着您有两个并排重复的类(\d\d*)。如果以错误的方式使用,这实际上可能是危险的,会使您的系统面临DoS攻击。

为了解决这个问题,我们需要将句点视为必需的(以分离重复的字符类),而不是将整个小数部分视为可选的,而不是将句点视为可选的:

\d+(\.\d+)? /* Better. But... */

现在看起来好多了。我们要求在第一个数字序列和第二个数字序列之间有一个句点,但有一个致命的缺陷:我们无法匹配.123,因为现在需要一个前导数字。

这实际上很容易修复。我们需要将数字的“十进制”部分视为一个字符序列,而不是可选的:1个或多个数字,其前缀可能是前缀可能为0或更多数字:

(\d*\.)?\d+

现在我们只需要加上标志:

[+-]?(\d*\.)?\d+

当然,这些斜杠在Java中非常烦人,因此我们可以在长格式字符类中替换:

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

这已经在评论中出现了好几次,所以我添加了一个关于匹配与验证的附录。

匹配的目标是在输入中找到一些内容(大海捞针)。验证的目标是确保输入符合预期的格式。

正则表达式本质上只匹配文本。给定一些输入,他们要么会找到一些匹配的文本,要么不会。但是,通过使用锚标记(^$)将表达式“捕捉”到输入的开头和结尾,我们可以确保除非整个输入与表达式匹配,否则不会找到匹配项,有效地使用正则表达式进行验证。

上述正则表达式([-]?([0-9]*[.])?[0-9])将匹配目标字符串中的一个或多个数字。因此,考虑到输入:

apple 1.34 pear 7.98 version 1.2.3.4

正则表达式将匹配1.347.981.2.3.4

要验证给定输入是否是一个数字,而不是一个数字,请通过将表达式包装在定位标记中,将其“捕捉”到输入的开始和结束处:

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

只有当整个输入是浮点数时,才会找到匹配,而如果输入包含其他字符,则不会找到匹配。因此,给定输入1.2,将找到匹配项,但是给定苹果1.2梨,将找不到匹配项。

请注意,一些正则表达式引擎有一个validateisMatch或类似的函数,它基本上实现了我所描述的自动功能,如果找到匹配项,则返回true,如果没有找到匹配项,则返回false。还请记住,某些引擎允许您设置标志,以更改^$的定义,匹配行的开始/结束,而不是整个输入的开始/结束。这通常不是默认设置,但请注意这些标志。

匿名用户

我认为在撰写本文时,本页上的任何答案都不正确(其他许多关于SO的建议也都是错误的)。复杂的是,您必须匹配以下所有可能性:

  • 没有小数点(即整数值)
  • 小数点前后的数字(例如0.3522.165
  • 只有小数点前的数字(例如0.1234.
  • 仅小数点后的数字(例如.0.5678

同时,您必须确保某处至少有一位数字,即不允许出现以下情况:

  • 小数点本身
  • 一个没有数字的有符号的小数点(即.-.
  • -自己
  • 一个空字符串

一开始这似乎很棘手,但找到灵感的一种方法是查看java的OpenJDK源代码。朗,双人。valueOf(String)方法(从http://hg.openjdk.java.net/jdk8/jdk8/jdk,单击“浏览”,向下导航/src/share/classes/java/lang/,并找到Double类)。该类包含的长正则表达式满足了OP可能没有想到的各种可能性,但为了简单起见,忽略了其中处理NaN、无穷大、十六进制表示法和指数的部分,并使用\d而不是POSIX表示法来表示一位数字,对于无指数的有符号浮点数,我可以将正则表达式的重要部分缩减为:

代码>[ -]?((\d\.?\d*)|(\.\d))

我不认为有办法避免<代码>(...)|(...)构造不允许不包含数字的东西,或者禁止小数点前没有数字或小数点后没有数字的可能性之一。

显然,在实践中,无论是在正则表达式本身还是在使用它的代码中,都需要考虑尾随或前置空格。

匿名用户

我想匹配大多数语言认为有效数字(整数和浮点):

>

'1.0'/'1'/'。1' / '-1.' / '-.1'

'0.45326e 04','666999e-05','0.2e-3','-33. e-1'

笔记:

>

  • 前面的数字符号('-'或'')是可选的

    '-1.'和'-.1'是有效的,但是'.'和'-.'是无效的

    “.1e3”有效,但无效。e3'和e3'无效

    为了同时支持'1.'和'1',我们需要一个OR运算符 ('|') 以确保从匹配中排除'.'。

    [-]/-sing是可选的,因为表示0或1个匹配项

    因为我们有两个子表达式,所以需要将它们放在括号中

    \d([.]\d*)?(e[-]?\d)这适用于以数字开头的数字

    |分隔子表达式

    [.]\d(e[-]?\d)?这是以'.'开头的数字。

    表达式的结束

    • 对于以“.”开头的数字

    [.]第一个字符是点(在括号内或是通配符)

    \d一个或多个数字

    (e[-]?\d)这是一个可选的(0或1匹配,因为结尾是“?”)科学符号

    • 对于数字开头的数字

    \d一个或多个数字

    ([.]\d*)?可选的,我们可以在它后面有一个零或更多位数的点字符

    (e[-]?\d)这是可选的科学符号

    • 科学记数法

    指定指数的文本

    [-]可选指数符号

    \d一个或多个数字

    所有这些加起来:

    [+-]?(\d+([.]\d*)?(e[+-]?\d+)?|[.]\d+(e[+-]?\d+)?)
    

    也接受E

    [+-]?(\d+([.]\d*)?([eE][+-]?\d+)?|[.]\d+([eE][+-]?\d+)?)
    

    (测试用例)