我的任务是匹配浮点数。我为它编写了以下正则表达式:
[-+]?[0-9]*\.?[0-9]*
但是,它返回一个错误:
Invalid escape sequence (valid ones are \b \t \n \f \r \" \' \\ )
据我所知,我们需要为使用转义字符代码>也是。请纠正我哪里错了。
使用[.]
而不是\.
和[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.34
,7.98
,1.2
,.3
和.4
。
要验证给定输入是否是一个数字,而不是一个数字,请通过将表达式包装在定位标记中,将其“捕捉”到输入的开始和结束处:
^[+-]?([0-9]*[.])?[0-9]+$
只有当整个输入是浮点数时,才会找到匹配,而如果输入包含其他字符,则不会找到匹配。因此,给定输入1.2
,将找到匹配项,但是给定苹果1.2梨
,将找不到匹配项。
请注意,一些正则表达式引擎有一个validate
、isMatch
或类似的函数,它基本上实现了我所描述的自动功能,如果找到匹配项,则返回true
,如果没有找到匹配项,则返回false
。还请记住,某些引擎允许您设置标志,以更改^
和$
的定义,匹配行的开始/结束,而不是整个输入的开始/结束。这通常不是默认设置,但请注意这些标志。
我认为在撰写本文时,本页上的任何答案都不正确(其他许多关于SO的建议也都是错误的)。复杂的是,您必须匹配以下所有可能性:
0.35
,22.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+)?)
(测试用例)