【问题标题】:How to detect a floating point number using a regular expression如何使用正则表达式检测浮点数
【发布时间】:2010-02-19 02:48:42
【问题描述】:

什么是处理浮点数的好正则表达式(即像Java的Float)

答案必须符合以下目标:

 1) 1.  
 2) .2   
 3) 3.14  
 4) 5e6  
 5) 5e-6  
 6) 5E+6  
 7) 7.e8  
 8) 9.0E-10  
 9) .11e12  

总之应该是

  • 忽略前面的符号
  • 要求小数点左边的第一个字符不为零
  • 允许小数点两边有 0 个或多个数字
  • 允许没有小数点的数字
  • 允许科学记数法
  • 允许大写或小写“e”
  • 允许正或负指数

对于那些想知道的人,是的,这是一个家庭作业问题。我们在我的编译器研究生 CS 课程中收到了这个作业。我已经为课程上交了我的答案,并将其作为对这个问题的答案发布。

[结语] 我的解决方案没有得到充分的评价,因为它处理的小数点左侧不超过 1 位。该作业确实提到了处理 Java 浮点数,即使没有一个示例的小数点左侧多于 1 位。我会在自己的帖子中发布接受的答案。

【问题讨论】:

  • 我个人会写一堆单元测试...
  • 这些都是很奇怪的要求。这样的表达式不会匹配“0.5”。

标签: regex floating-point


【解决方案1】:

只需将小数点和 E-then-exponent 部分都设为可选:

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

我不明白您为什么不希望领先的 [+-]? 也捕获可能的标志,但是,无论如何!-)

编辑:实际上小数点后面可能没有数字(在这种情况下,我想必须是小数点 1+ 数字!),因此显然需要垂直条(替代):

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

【讨论】:

  • 请注意,这与 .x0.x 形式的任何内容都不匹配。
  • @Alex:如果它是表达式的一部分,他可能不想捕获符号,例如“5-2.5”。如果您要对事物进行标记,这是预期的,就像您在编写编译器时一样。
  • 您可能需要注意在需要匹配的示例列表中明确存在.2。我想这是需要明确规范的地方。 ://
  • 啊哈,好点子。那么肯定需要一个竖线来表示小数点左边可能没有数字的事实,但是,如果有,那么第一个必须是非零的。让我编辑 A 以显示这一点。
  • 此模式与“0”或“0.7”不匹配。这是我的修改:-?(0(\.\d*)?|([1-9]\d*\.?\d*)|(\.\d+))([Ee][+-]?\d+)?
【解决方案2】:

[这是教授的回答]

定义:

N = [1-9]
D = 0 | N
E = [eE] [+-]? D+
L = 0 | (N D*)

然后浮点数可以匹配:

( ( L . D* | . D+ ) E? ) | ( L E )

也可以使用 D+ 而不是 L,并在前面加上 [+-]?。

一个常见的错误是写 D* 。 D*,但这只能匹配 '.'。

[编辑]
有人问一个领先的标志;我应该问他为什么它被排除在外,但一直没有机会。由于这是语法讲座的一部分,我的猜测是,要么它使问题变得更容易(不太可能),要么在解析问题集的地方有一个小细节,这样无论符号如何,浮点值都是焦点(可能)。

如果您正在通过表达式进行解析,例如

-5.04e-10 + 3.14159E10

浮点值的符号是应用于该值的操作的一部分,而不是数字本身的属性。换句话说,

减去 (5.04e-10)
添加(3.14159E10)

形成表达式的结果。虽然我确信数学家可能会争论这一点,但请记住这是来自解析讲座。

【讨论】:

  • Infinity 和 NaN 怎么样?
  • 由于这个练习是关于解析一种语言的,我冒昧地认为语法需要定义表示这些概念的标记,假设它们被允许作为输入。
【解决方案3】:
【解决方案4】:

这是我上交的。

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

为了便于讨论,我将标记这些部分

( ([1-9]+ \. [0-9]* ) | ( [1-9]* \. [0-9]+ ) | ([1-9]+))  ( [eE] [-+]? [0-9]+ )?     
--------------------------------------------------------  ----------------------    
                           A                                       B

A:匹配直到“e/E”的所有内容
B:符合科学记数法

分解 A 我们得到三个部分

 ( ([1-9]+ \. [0-9]* ) | ( [1-9]* \. [0-9]+ ) | ([1-9]+) )
   ----------1----------   ---------2----------   ---3----

第 1 部分:允许 1-9 的 1 位或多位数字、小数点、小数点后的 0 位或多位数字(目标 1)
第 2 部分:允许 0 位或更多位从 1-9、小数、小数点后 1 位或更多位(目标 2)
第 3 部分:允许 1-9 中的 1 位或更多位不带小数(参见目标列表中的 #4)


分解 B 我们得到 4 个基本部分

 ( [eE] [-+]? [0-9]+  )?   
   ..--1- --2-- --3--- -4- .. 

第 1 部分:科学记数法需要大写或小写“e”(例如目标 8 和 9)
第 2 部分:允许对指数使用可选的正号或负号(例如目标 4、5 和 6)
第 3 部分:允许 1 位或更多位的指数(目标 8)
第 4 部分:允许科学记数法作为一个组是可选的(目标 3)

【讨论】:

  • 您的 (A) 的第一部分 (1) 不允许 10.
  • (A) 的第 (1) 部分可能应该是 ([1-9][0-9]*\.[0-9]*)。第 (3) 部分需要进行类似的更改。
  • @tur1ng: true 但归咎于测试输入! 8-)
  • @tur1ng,事实证明我的解决方案正是因为这个原因而被标记。教授确实承认示例输入不完整,但表示这些只是示例,而不是问题的整个领域。
【解决方案5】:

@Kelly S. French,这个正则表达式匹配你所有的测试用例。

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

来源:perldoc perlretut

【讨论】:

    【解决方案6】:
    '([-+])?\d*(\.)?\d+(([eE]([-+])?)?\d+)?'
    

    这是我在 Matlab 中尝试解决此类任务时得出的正则表达式。实际上,它不会正确检测像 (1.) 这样的数字,但一些额外的更改可能会解决问题......好吧,也许以下可以解决这个问题:

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

    【讨论】:

      【解决方案7】:

      @Kelly S. French:该符号丢失是因为在解析器中它会被一元减号(否定)表达式添加,因此不需要将其检测为浮点数的一部分。

      【讨论】:

        猜你喜欢
        • 2012-08-16
        • 2012-09-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多