【问题标题】:Regular expression for floating point numbers浮点数的正则表达式
【发布时间】:2012-09-20 12:22:34
【问题描述】:

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

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

但是,它返回一个错误:

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

据我所知,我们还需要为 . 使用转义字符。请纠正我的错误。

【问题讨论】:

  • 这个正则表达式使用什么语言?
  • @JDB - 你为什么要为一个数字/浮点正则表达式放弃 100 分?该标准一直是(?:\d+(?:\.\d*)?|\.\d+),并已在 SO...上无限发布...
  • [-+]?([0-9]*[.])?[0-9]+([eE][-+]?\d+)? 如果你也想捕捉指数符号,例如 3.023e-23
  • 在某些语言(如 Java 或 C++)中,必须对反斜杠进行转义。因此,要获得正则表达式“\.”,您将使用字符串“\\.”。 Python 通过使用原始字符串来解决这个问题。

标签: regex


【解决方案1】:

在 C 语言中,答案是这样的:

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

【讨论】:

    【解决方案2】:

    TL;DR

    使用[.] 代替\. 和[0-9] 代替\d 以避免在某些语言(如Java)中出现转义问题。

    感谢 the nameless one 最初认识到这一点。

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

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

    这将匹配:

    • 123
    • 123.456
    • .456

    查看working example

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

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

    请参阅 pkeller's answer 以获取有关此模式的更完整说明

    如果您想包含更广泛的数字,包括科学记数法和十六进制和八进制等非十进制数字,请参阅我对How do I identify if a string is a number? 的回答。

    如果您想验证输入是一个数字(而不是在输入中查找数字),那么您应该用^ 和$ 将模式括起来,如下所示:

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

    不规则正则表达式

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

    (顺便说一句,为了减少混淆,许多人开始使用“regex”或“regexp”来描述这些增强的匹配语言。请参阅 RexEgg 的 Is a Regex the Same as a Regular Expression? .com 了解更多信息。)

    也就是说,大多数正则表达式引擎(实际上,据我所知,所有引擎)都会接受\.。很可能是转义存在问题。

    逃跑的麻烦

    某些语言内置了对正则表达式的支持,such as 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 = "\\.";
    

    所有这些转义都会变得非常混乱。如果您使用的语言支持raw strings,那么您应该使用它们来减少反斜杠的数量,但并非所有语言都支持(最值得注意的是:Java)。幸运的是,有一个替代方案在某些时候会起作用:

    String correctPattern = "[.]";
    

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

    关于匹配数字的注意事项

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

    匹配一个数字是您认为使用正则表达式很容易的事情之一,但实际上非常棘手。让我们逐个看一下您的方法:

    [-+]?
    

    匹配可选的- 或+

    [0-9]*
    

    匹配 0 个或多个连续数字

    \.?
    

    匹配一个可选的.

    [0-9]*
    

    匹配 0 个或多个连续数字

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

    [0-9] = \d

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

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

    要解决此问题,首先使用所需的最少字符串(可能是单个数字)“锚定”您的正则表达式会很有帮助:

    \d+
    

    现在我们要添加小数部分,但它并没有达到您认为的效果:

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

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

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

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

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

    这实际上很容易解决。我们不需要将数字的“小数”部分设为可选,而是将其视为一个字符序列:1 个或多个数字可能以 . 为前缀,而. 可能以 0 或多个数字为前缀:

    (\d*\.)?\d+
    

    现在我们只需添加符号:

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

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

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

    匹配与验证

    这在 cmets 中出现过几次,所以我添加了关于匹配与验证的附录。

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

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

    上述正则表达式 ([+-]?([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,将找到匹配项,但给定 apple 1.2 pear 则找不到匹配项。

    请注意,某些正则表达式引擎具有 validate、isMatch 或类似函数,它基本上自动完成我所描述的操作,如果找到匹配项则返回 true,如果不匹配则返回 false被发现。另请记住,某些引擎允许您设置更改^ 和$ 定义的标志,匹配行的开头/结尾而不是整个输入的开头/结尾。这通常不是默认设置,但请注意这些标志。

    【讨论】:

    • JDB,谢谢,我希望你还在!我将来会阅读您的帖子:)您的答案肯定会处理 0.24 和 2.2 并且正确地不允许 4.2.44 全部使用regex101.com 进行测试但是,它不允许 123. 正如您所说的那样可能是可以接受的(我认为是!)。我可以通过将您的表达式更改为 [-+]?(\d*[.])?\d* 来解决这个问题(注意 * 在末尾而不是 +),然后是疯狂的事情,例如 . (你的第二个例子)是允许的。无论如何要我的蛋糕也吃吗?
    • @Dave - \d+(\.\d*)?|\.\d+
    • @yeouuu 是的,因为 1. 匹配。如果您只想在整个输入匹配时进行匹配,请将^ 和$ 添加到正则表达式的开头和结尾。
    • 浮点数可以有指数或者是 NaN/Inf,所以我会使用这个:[-+]?(([0-9]*[.]?[0-9]+([ed][-+]?[0-9]+)?)|(inf)|(nan)), e/d 表示浮点数/双精度浮点数。不要忘记正则表达式的折叠大小写标志
    • 我建议使用非捕获组,因为我们不太可能有人旨在仅捕获数字的整数部分。像这样:[+-]?(?:[0-9]*[.])?[0-9]+。然后,捕获整个数字是微不足道的。
    【解决方案3】:
    (\d*)(\.)*(\d+)
    

    这将解析以下内容。

    11.00
    12
    .0
    

    必须有一个数字。小数点和小数点前的数字是可选的。

    【讨论】:

      【解决方案4】:
      ^[+-]?([0-9]{1,})[.,]([0-9]{1,})$
      

      这将匹配:

      1. 1.2
      2. 12.3
      3. 123.4
      4. 1,2
      5. 12,3
      6. 123,4

      【讨论】:

        【解决方案5】:

        这会捕获 C/C++ 代码中识别的浮点数:

        [+-]?((((\d+\.?\d*)|(\.\d+))([eE][+-]?\d+[fF]?)?)|((\d+\.\d*)|(\.\d+))[fF]?)
        
        • +/- 符号
        • 只有数字、数字、.digits 或digits.digits
        • 带有 e 或 E、+/- 符号和数字的可选指数
        • 末尾可选 f 或 F,但仅当数字包含 a 时。或指数

        【讨论】:

          【解决方案6】:

          对于那些搜索将验证一个整个输入的正则表达式的人,该输入应该是一个有符号浮点数点数用户输入的字符。

          即首先是符号(应该匹配并且有效),然后是所有数字(仍然匹配并且有效)及其可选的小数部分。

          在 JS 中,我们使用 onkeydown/oninput 事件来执行此操作 + 以下正则表达式:

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

          【讨论】:

            【解决方案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 运算符 ('|') 以确保我们排除 '.'来自匹配。

            [+-]? +/- 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+)?)
            

            也接受E:

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

            (Test cases)

            【讨论】:

              【解决方案8】:

              在 c 表示法中,浮点数可以以下列形式出现:

              1. 123
              2. 123.
              3. 123.24
              4. .24
              5. 2e-2 = 2 * 10 pow -2 = 2 * 0.1
              6. 4E+4 = 4 * 10 pow 4 = 4 * 10 000

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

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

              现在,我将编写小块浮点正则表达式 - 解决方案是用符号“|”连接这些块。

              块:

              - (([+-]?{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})
              

              【讨论】:

                【解决方案9】:

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

                答案是这样的:

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

                请注意,我没有使用标志符号,如果你想要它带有标志符号,它会这样:

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

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

                【讨论】:

                  【解决方案10】:

                  对于 JavaScript

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

                  适用于 1.23 1234.22 0 0.12 12

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

                  【讨论】:

                    【解决方案11】:

                    在撰写本文时,我认为此页面上的任何答案都不正确(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/ 并找到 @987654334 @ 班级)。此类包含的长正则表达式满足了 OP 可能没有想到的各种可能性,但为简单起见,忽略了处理 NaN、无穷大、十六进制表示法和指数的部分,并使用 \d 而不是一个数字的 POSIX 表示法,我可以将正则表达式的重要部分减少为没有指数的有符号浮点数:

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

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

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

                    【讨论】:

                    • @JDB 你是对的,很抱歉在你的评论中遗漏了版本。我担心的是,在接受的答案中最突出的正则表达式不适用于所有情况。感谢您链接到/包括我的建议。
                    • 这个以及所有/大多数其他答案都忽略了浮点数可以有指数。
                    • @NateS 没错,我确实写了“为简单起见,忽略处理 NaN、无穷大、十六进制表示法和指数的部分”,因为这似乎与 OP 问题的范围相匹配。周围有更完整的实现,包括我在 JDK 源代码中找到的那个。
                    • 可以使用正则表达式[+-]?((?=\.?\d)\d*\.?\d*) 来避免交替吗?它使用前瞻...
                    • @4esn0k 不错的正则表达式!我玩过它,它确实有效。我有两个警告:(1)并非所有正则表达式引擎都支持零宽度断言(尽管大多数现代引擎支持,AFAIK),以及(2)前瞻只是另一个名称的替代:引擎仍然需要尝试一些东西如果它不起作用,则回溯。尽管如此,还是要对一个非常巧妙的想法投赞成票。
                    【解决方案12】:
                    [+/-] [0-9]*.[0-9]+
                    

                    试试这个解决方案。

                    【讨论】:

                      【解决方案13】:
                      [+-]?(([1-9][0-9]*)|(0))([.,][0-9]+)?
                      

                      [+-]? - 可选的前导符号

                      (([1-9][0-9]*)|(0)) - 不带前导零的整数,包括单个零

                      ([.,][0-9]+)? - 可选小数部分

                      【讨论】:

                      • 提供更多信息 - 对于不知道正则表达式的人来说,它是象形文字。对于认识他们的人来说,他们不需要它。
                      【解决方案14】:

                      这个对我有用:

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

                      你也可以使用这个(不带命名参数):

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

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

                      【讨论】:

                        【解决方案15】:

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

                        【讨论】:

                          【解决方案16】:

                          你需要的是:

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

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

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

                          0
                          +1
                          -2.0
                          2.23442
                          

                          【讨论】:

                          • 这个表达式的问题是 .1 是不允许的,即使这样的输入被普遍认为是正确的。
                          • 现在将接受零长度字符串- 和+,它们不是数字。正则表达式很棘手! :)
                          • 另外,这并不能回答 OP 的实际问题,即 \. 不起作用。
                          猜你喜欢
                          • 1970-01-01
                          • 1970-01-01
                          • 1970-01-01
                          • 1970-01-01
                          • 2022-11-21
                          • 2014-04-25
                          • 1970-01-01
                          • 1970-01-01
                          相关资源
                          最近更新 更多