浮点数的正则表达式


115

我有一个任务要匹配浮点数。我为此编写了以下正则表达式:

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

但是,它返回一个错误:

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

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


10
此正则表达式使用什么语言?
CaffGeek 2012年

3
@JDB-为什么要为数字/浮点正则表达式给100点?该标准一直以来(?:\d+(?:\.\d*)?|\.\d+)都被无限期地发布在SO ...


1
[-+]?([0-9]*[.])?[0-9]+([eE][-+]?\d+)?如果您也想采用指数表示法,例如3.023e-23
wcochran

在某些语言(例如Java或C ++)中,必须转义反斜杠。因此,要获取正则表达式“ \。”,您将使用字符串“ \\。”。Python通过使用原始字符串来解决此问题。
HackerBoss

Answers:


257

TL; DR

使用[.]代替\.[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 ”来描述这些增强的匹配语言。有关更多信息,请参见RexEgg.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的字符串;仅由+or 组成的字符串-;或者,仅由组成的字符串.。这可能不是您想要的。

要解决此问题,从用最小的必需字符串(可能是一个数字)“固定”正则表达式开始会很有帮助:

\d+

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

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

仍然会匹配的值123.。更糟糕的是,它带有一种邪恶色彩。句点是可选的,这意味着您有两个并排重复的类(\d+\d*)。如果以错误的方式使用,这实际上很危险,从而使您的系统容易受到DoS攻击。

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

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

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

这实际上很容易解决。而不是使数字的“小数”部分为可选,我们需要将其视为一个字符序列:1个或多个可以以a为前缀的数字,也可以以.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,将找到一个匹配项,但apple 1.2 pear没有找到匹配项。

需要注意的是一些正则表达式引擎有一个validateisMatch或类似的功能,基本上做什么,我已自动描述,返回true如果找到匹配且false如果没有发现匹配。也请记住,有些引擎允许你改变它的定义组标志^$,一条线的开始/结束,而不是整个输入的开始/结束匹配。通常这不是默认值,但是请注意这些标志。


2
JDB,谢谢,希望您还在!我将来会在阅读您的帖子:)您的回答肯定会处理0.24和2.2,并且正确地禁止了4.2.44使用regex101.com进行了所有测试。但是,它不允许了123。正如您所说的那样(我认为可以接受)是!)。我可以通过将您的表达式更改为[-+]?(\ d * [。])?\ d *(注意*而不是+结束)来解决这个问题,然后再使用诸如的疯狂方法。(第二个示例)是允许的。反正也要吃我的蛋糕吗?
戴夫

2
@戴夫-\d+(\.\d*)?|\.\d+
加多宝还记得莫妮卡

/[-+]?(\d*[.])?\d+/.test("1.bc") // returns true
yeouuu '16

1
@yeouuu是的,因为1.匹配。如果只想在整个输入匹配的情况下进行匹配,则在正则表达式的开头和结尾处添加^$
JDB仍然记得Monica

5
浮点数可以有指数,也可以是NaN / Inf,所以我将使用: [-+]?(([0-9]*[.]?[0-9]+([ed][-+]?[0-9]+)?)|(inf)|(nan))e / d表示浮点数/双精度浮点数。不要忘记对正则表达式使用折痕标志
Markus Schmassmann '16

23

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

  • 无小数点(即整数值)
  • 之前和之后的小数点位数(例如:0.3522.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,无穷大,十六进制表示法和指数的部分,并且使用\dPOSIX表示法而不是一位数字,我可以将正则表达式的重要部分简化为带符号的浮点数,而无需指数:

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

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

显然,实际上,您将需要在正则表达式本身或使用它的代码中满足尾随或前导空格。


如果您添加要求以匹配数字,例如123.,那么...是或开关是唯一的解决方案,正如我在原始帖子的评论中指出的那样。
JDB仍记得莫妮卡

1
这个以及所有/大多数其他答案都忽略了浮点数可以具有指数。
NateS

1
@NateS是的,我确实写过“为简单起见,忽略了涉及NaN,无穷大,十六进制表示法和指数的部分”,因为这似乎符合OP的问题范围。周围有更完整的实现,包括我在JDK源代码中找到的实现。
pkeller

1
可以使用正则表达式[+-]?((?=\.?\d)\d*\.?\d*)来避免这种交替吗?它使用了前瞻性...
4esn0k

1
@ 4esn0k好的正则表达式!我玩过它,它确实起作用。我有两个警告:(1)并非所有的正则表达式引擎都支持零宽度断言(尽管大多数现代正则表达式引擎都支持AFAIK),以及(2)前瞻只是另一种名称的替代:引擎仍必须尝试一些操作然后返回,如果它不起作用。尽管如此,请赞成一个非常整洁的想法。
pkeller

7

您需要的是:

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

我转义了“ +”和“-”符号,并且也将小数点后面的数字分组,因为类似“ 1”。不是有效数字。

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

0
+1
-2.0
2.23442

该表达式的问题在于.1,即使这种输入被普遍认为是正确的,也不允许这样做。
JDB仍记得Monica 2012年

现在,它将接受零长度的字符串-+,它们不是数字。正则表达式很棘手!:)
JDB仍然记得Monica

另外,这不能回答OP的实际问题,即那\.是行不通的。
JDB仍记得Monica

7

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

  • '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运算符('|'),以确保排除'。'。从匹配。

[+-]?+/-是可选的,因为?意味着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+)?)

也要接受E

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

测试用例


4

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


您可能是正确的...错误消息看起来像是编程语言语法错误,而不是正则表达式解析器错误。
JDB仍然记得Monica

3

这个为我工作:

(?P<value>[-+]*\d+\.\d+|[-+]*\d+)

您也可以使用此命令(不带命名参数):

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

使用一些在线正则表达式测试器进行测试(例如regex101)


2
^[+]?([0-9]{1,2})*[.,]([0-9]{1,1})?$

这将匹配:

  1. 1.2
  2. 12.3
  3. 1,2
  4. 12,3

尽管此代码段是受欢迎的,并且可能会提供一些帮助,但是如果它包含有关如何以及为什么可以解决此问题的说明,则可以大大改善。请记住,您将来会为读者回答问题,而不仅仅是现在问的人!请编辑您的答案以添加说明,并指出适用的限制和假设。
Toby Speight

哦,谢谢,我对此很感兴趣
Serg Burlaka


0

在C ++中使用正则表达式库

答案会像这样:

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

请注意,我不使用符号符号,如果您希望将其与符号符号一起使用,它将解决此问题:

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

这也分隔了常规数字或十进制数字。


0

用符号表示时,浮点数可能会出现以下形状:

  1. 123
  2. 123。
  3. 123.24
  4. .24
  5. 2e-2 = 2 * 10战俘-2 = 2 * 0.1
  6. 4E + 4 = 4 * 10战俘4 = 4 * 10000

为了创建float常规表达式,我将首先创建“ int常规表达式变量”:

(([1-9][0-9]*)|0) will be int

现在,我将编写小块的float常规表达式-解决方案是用或simbol“ |”合并这些块。

块:

- (([+-]?{int}) satysfies case 1
- (([+-]?{int})"."[0-9]*)  satysfies cases 2 and 3
- ("."[0-9]*) satysfies case 4
- ([+-]?{int}[eE][+-]?{int}) satysfies cases 5 and 6

最终解决方案(包含小块):

(([+-]?{int})|(([+-]?{int})"."[0-9]*)|("."[0-9]*)|([+-]?{int}[eE][+-]?{int})


-1

对于javascript

const test = new RegExp('^[+]?([0-9]{0,})*[.]?([0-9]{0,2})?$','g');

适用于1.23 1234.22 0 0.12 12

您可以更改中的部分,{}以得到十进制长度和十进制前面的不同结果。用于输入中,用于输入数字并在键入时检查每个输入,仅允许通过。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.