浮点数的正则表达式

Gop*_*ant 87 regex

我有一个匹配浮点数的任务.我为它写了以下正则表达式:

[-+]?[0-9]*\.?[0-9]*
Run Code Online (Sandbox Code Playgroud)

但它显示错误说:

Invalid escape sequence (valid ones are  \b  \t  \n  \f  \r  \"  \'  \\ )
Run Code Online (Sandbox Code Playgroud)

但据我所知,我们还需要使用转义字符..请纠正我错在哪里.

JDB*_*JDB 213

TL; DR

使用[.]的,而不是\.[0-9]代替\d,以避免在某些语言(如Java)逃逸的问题.

感谢无名的人最初认识到这一点.

用于匹配浮点数的一个相对简单的模式是

[+-]?([0-9]*[.])?[0-9]+
Run Code Online (Sandbox Code Playgroud)

这将匹配:

  • 123
  • 123.456
  • .456

查看一个工作示例

如果你还想匹配123.(一个没有小数部分的句号),那么你需要一个稍长的表达式:

[+-]?([0-9]+([.][0-9]*)?|[.][0-9]+)
Run Code Online (Sandbox Code Playgroud)

请参阅pkeller的答案,以更全面地解释这种模式

如果要包含非十进制数字,例如十六进制和八进制,请参阅我的答案如何识别字符串是否为数字?.

如果你想验证输入是一个数字(而不是在输入中找到一个数字),那么你应该用^和包围模式$,如下所示:

^[+-]?([0-9]+([.][0-9]*)?|[.][0-9]+)$
Run Code Online (Sandbox Code Playgroud)

不规则的正则表达式

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

(顺便说一句,为了帮助减少混淆,许多人已经开始使用" regex "或" regexp "来描述这些增强的匹配语言.有关详细信息,请参阅RexEgg.com上的Regex与正则表达式相同吗?)

也就是说,大多数正则表达式引擎(实际上,就我所知,所有这些引擎都会接受)\..最有可能的是逃避问题.

逃离的麻烦

有些语言内置了对正则表达式的支持,例如JavaScript.对于那些没有的语言,转义可能是个问题.

这是因为您基本上使用语言编写语言.例如,Java \在其字符串中用作转义字符,因此如果要在字符串中放置文字反斜杠字符,则必须将其转义:

// creates a single character string: "\"
String x = "\\";
Run Code Online (Sandbox Code Playgroud)

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

// Creates a two-character string: "\\"
// When used as a regex pattern, will match a single character: "\"
String regexPattern = "\\\\";
Run Code Online (Sandbox Code Playgroud)

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

// will most likely result in an "Illegal escape character" error
String wrongPattern = "\.";
// will result in the string "\."
String correctPattern = "\\.";
Run Code Online (Sandbox Code Playgroud)

所有这些逃避都会变得非常混乱.如果您使用的语言支持原始字符串,那么您应该使用它们来减少反斜杠的数量,但不是所有语言都这样做(最值得注意的是:Java).幸运的是,有一种替代方案可以在某些时候起作用:

String correctPattern = "[.]";
Run Code Online (Sandbox Code Playgroud)

对于一个正则表达式引擎,\.[.]意味着完全一样的东西.请注意,这并不适用于所有情况,例如newline(\\n),open square bracket(\\[)和反斜杠(\\\\[\\]).

关于匹配数字的注记

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

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

[-+]?
Run Code Online (Sandbox Code Playgroud)

匹配可选-+

[0-9]*
Run Code Online (Sandbox Code Playgroud)

匹配0个或更多个连续数字

\.?
Run Code Online (Sandbox Code Playgroud)

匹配可选项 .

[0-9]*
Run Code Online (Sandbox Code Playgroud)

匹配0个或更多个连续数字

首先,我们可以通过使用数字的字符类缩写来清理这个表达式(请注意,这也容易受到上面提到的转义问题的影响):

[0-9] = \d

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

现在,如果仔细观察,你会发现你的模式的每一部分都是可选的.此模式可以匹配0长度的字符串; 仅由+或组成的字符串-; 或者,仅由a组成的字符串..这可能不是你想要的.

要解决这个问题,首先要使用最小的必需字符串"锚定"正则表达式,这可能是一个数字:

\d+
Run Code Online (Sandbox Code Playgroud)

现在我们要添加小数部分,但它不会出现在您认为可能的位置:

\d+\.?\d* /* This isn't quite correct. */
Run Code Online (Sandbox Code Playgroud)

这仍然会匹配像这样的值123..更糟糕的是,它有一丝邪恶.这段时间是可选的,这意味着你有两个重复的课程并排(\d+\d*).如果以错误的方式使用,将系统打开到DoS攻击,这实际上可能是危险的.

要解决这个问题,不要将句点视为可选,我们需要根据需要对其进行处理(分隔重复的字符类),而是将整个小数部分设为可选:

\d+(\.\d+)? /* Better. But... */
Run Code Online (Sandbox Code Playgroud)

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

这实际上很容易修复.我们不需要将数字的"十进制"部分作为可选项,而是将其视为一系列字符:一个或多个可以带前缀的数字,可以带有.0或更多数字的前缀:

(\d*\.)?\d+
Run Code Online (Sandbox Code Playgroud)

现在我们只需添加标志:

[+-]?(\d*\.)?\d+
Run Code Online (Sandbox Code Playgroud)

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

[+-]?([0-9]*[.])?[0-9]+
Run Code Online (Sandbox Code Playgroud)

匹配与验证

这已经在评论中出现了几次,所以我在补充和验证方面添加了一个附录.

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

就其性质而言,正则表达式仅匹配文本.给定一些输入,他们会找到一些匹配的文本,或者他们不会.但是,通过使用锚标记(^$)将表达式"捕捉"到输入的开头和结尾,我们可以确保找不到匹配,除非整个输入与表达式匹配,有效地使用正则表达式进行验证.

上面描述的正则表达式([+-]?([0-9]*[.])?[0-9]+)将匹配目标字符串中的一个或多个数字.所以给出了输入:

apple 1.34 pear 7.98 version 1.2.3.4
Run Code Online (Sandbox Code Playgroud)

正则表达式匹配1.34,7.98,1.2,.3.4.

要验证给定输入是一个数字而不是数字,通过将表达式包装在锚标记中,将表达式"捕捉"到输入的开头和结尾:

^[+-]?([0-9]*[.])?[0-9]+$
Run Code Online (Sandbox Code Playgroud)

如果整个输入是浮点数,则只会找到匹配项,如果输入包含其他字符,则不会找到匹配项.因此,给定输入1.2,将找到匹配,但是apple 1.2 pear没有找到匹配.

需要注意的是一些正则表达式引擎有一个validate,isMatch或类似的功能,基本上做什么,我已自动描述,返回true如果找到匹配且false如果没有发现匹配.还要记住,某些引擎允许您设置标志,这些标志会更改和的定义,^$匹配行的开头/结尾而不是整个输入的开头/结尾.这通常不是默认值,而是要注意这些标志.

  • 浮点数可以有指数或是NaN/Inf,所以我会用这个:`[ - +]?(([0-9]*[.]?[0-9] +([ed] [ - +]?[ 0-9] +)?)|(inf)|(nan))`,e/d用于浮点/双精度浮点数.不要忘记正则表达式的折叠案例标志 (5认同)
  • 我建议使用非捕获组,因为不太可能有人旨在仅捕获数字的整数部分。像这样:`[+-]?(?:[0-9]*[.])?[0-9]+`。然后,捕获整个数字就很简单了。 (3认同)
  • JDB,谢谢,希望您还在!我将来会在阅读您的帖子:)您的回答肯定会处理0.24和2.2,并且正确地禁止了4.2.44使用http://regex101.com/进行了所有测试,但是,它不允许了123。 (我认为是!)。我可以通过将您的表达式更改为[-+]?(\ d * [。])?\ d *(注意*而不是+结束)来解决此问题,然后再执行诸如的疯狂操作。(您的第二个示例)是允许的。反正也要吃我的蛋糕吗? (2认同)
  • @Dave - `\ d +(\.\ d*)?| \.\ d +` (2认同)

pke*_*ler 23

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

  • 没有小数点(即整数值)
  • 无论是小数点前后的数字(例如0.35,22.165)
  • 小数点前的数字只(例如0.,1234.)
  • 小数点后的数字只(例如.0,.5678)

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

  • 自己的小数点
  • 带符号的小数点,没有数字(即+.-.)
  • +或者-靠自己
  • 一个空字符串

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

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

我不认为有一种方法可以避免(...)|(...)构造而不允许任何不包含数字的东西,或者禁止在小数点之前没有数字或者之后没有数字的可能性之一.

显然,在实践中,您需要在正则表达式本身或使用它的代码中处理尾随或前面的空格.

  • @JDB你是对的,很抱歉在你的评论中错过了版本。我担心的是,在接受的答案中最突出的正则表达式并不适用于所有情况。感谢您链接到/包括我的建议。 (2认同)
  • 这和所有/大多数其他答案都忽略了浮点数可以有指数。 (2认同)
  • 可以使用正则表达式 `[+-]?((?=\.?\d)\d*\.?\d*)` 来避免交替吗?它使用前瞻... (2认同)
  • @4esn0k 不错的正则表达式!我已经尝试过它,它确实有效。我有两个警告:(1)并非所有正则表达式引擎都支持零宽度断言(尽管大多数现代引擎都支持零宽度断言),(2)前瞻只是另一个名称的替代:引擎仍然需要尝试一些东西如果不起作用就回溯。尽管如此,还是对一个非常好的想法投赞成票。 (2认同)

小智 17

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

  • '5' / '-5'

  • '1.0' / '1.' / '.1' / '-1.' / '-.1'

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

笔记:

  • preceding sign of number ('-' or '+') is optional

  • '-1.' and '-.1' are valid but '.' and '-.' are invalid

  • '.1e3' is valid, but '.e3' and 'e3' are invalid

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

[+-]?+/- sing 是可选的,因为?意味着 0 或 1 个匹配

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

\d+([.]\d*)?(e[+-]?\d+)? 这是针对以数字开头的数字

| 分隔子表达式

[.]\d+(e[+-]?\d+)? 这是针对以“.”开头的数字

) 表达式结束

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

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

\d+ 一位或多位数字

(e[+-]?\d+)? 这是一个可选的(0 或 1 匹配由于结尾“?”)科学记数法

  • 对于以数字开头的数字

\d+ 一位或多位数字

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

(e[+-]?\d+)? 这是一个可选的科学记数法

  • 科学计数法

e 指定指数的文字

[+-]? 可选指数符号

\d+ 一位或多位数字

所有这些结合起来:

[+-]?(\d+([.]\d*)?(e[+-]?\d+)?|[.]\d+(e[+-]?\d+)?)
Run Code Online (Sandbox Code Playgroud)

也接受E

[+-]?(\d+([.]\d*)?([eE][+-]?\d+)?|[.]\d+([eE][+-]?\d+)?)
Run Code Online (Sandbox Code Playgroud)

测试用例


Div*_*com 7

你需要的是:

[\-\+]?[0-9]*(\.[0-9]+)?
Run Code Online (Sandbox Code Playgroud)

我转义了"+"和" - "符号,并将小数与其后续数字分组,因为类似于"1".不是有效的数字.

这些更改将允许您匹配整数和浮点数.例如:

0
+1
-2.0
2.23442
Run Code Online (Sandbox Code Playgroud)


the*_*one 6

这很简单:您已经使用过 Java 并且您应该使用\\.而不是\.(在 Java 中搜索字符转义)。


use*_*501 5

使用 C++ 库匹配 C 和 C++(以及许多其他语言)编译器认为浮点值的有效表示形式的字符串regex

在 C++ 中#include <regex>你可以这样做:

std::regex r("[+-]?[0-9]+[.][0-9]*([e][+-]?[0-9]+)?");
return std::regex_match(value, r);
Run Code Online (Sandbox Code Playgroud)

这比上面大多数与 C++ 相关的答案要简单得多。

它匹配 C++ 编译器认为是浮点数的有效字符串表示形式的字符串。

这意味着像这样的事情

1.
-1.
Run Code Online (Sandbox Code Playgroud)

被认为是浮点数的有效表示,但是

.1
-.1
Run Code Online (Sandbox Code Playgroud)

不是。

更详细地解释该表达式,它本质上由两部分组成:

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

[+-]?[0-9]+[.][0-9]*
and                 ([e][+-]?[0-9]+)?
Run Code Online (Sandbox Code Playgroud)

第一部分很容易理解:

  • 可选(表示出现 0 或 1 次)“+”或“-”字符
  • 至少 1 位数字,或多于一位数字
  • 字面上的“.” 字符,这是强制性的(否则您将得到整数而不是浮点值的表示)
  • 如果你想要“.” 如果是可选的,请将其更改为[.]?
  • 后跟零个或多个数字

一旦分解,第二部分也很容易。

  • 首先请注意,表达式包含在括号中,后跟?. 这意味着括号内的表达式必须匹配 0 或 1 次。(这意味着它是可选的。)
  • 里面有一个必须匹配的文字“e”字符
  • 后跟可选的“+”或“-”字符
  • 后跟 1 个或多个数字

最后一部分[+-]?[0-9]+是用于匹配整数的正则表达式。

要匹配整数值,请使用:

[+-]?[0-9]+[.]?[0-9]*([e][+-]?[0-9]+)?
Run Code Online (Sandbox Code Playgroud)

注意?后面的[.].

但请注意,这也会匹配诸如

+100e+100
Run Code Online (Sandbox Code Playgroud)

这可能是一个不寻常的整数表示。尽管从技术上讲它是一个整数,但您可能不会期望这是一个匹配。

如果您不想要这种行为,其他答案提供了解决方案。

为了确保整个字符串是匹配的,而不仅仅是包含匹配的字符串,请使用锚:

"^[+-]?[0-9]+[.][0-9]*([e][+-]?[0-9]+)?$"
Run Code Online (Sandbox Code Playgroud)

例子

没有锚定字符

没有锚定字符

与主播角色

在此输入图像描述

带有可选'.'字符:

在此输入图像描述

请注意,这与字符串匹配.-100.1e100如果不包含锚字符,这可能不是您想要的。

当考虑这个问题时:

我的目标是验证用户输入,以确保它与浮点数的有效 C++ 字符串表示匹配。因此,我假设您将使用锚字符并且您不考虑像这样的字符串

hello world 3.14 this contains a floating point number
Run Code Online (Sandbox Code Playgroud)

是一个有效的浮点数 - 因为虽然字符串包含一个浮点数,但整个字符串不是一个有效的浮点数。

如果您只想检测较大字符串/文本中的浮点,其他答案可能更适合您的需求。