【问题标题】:Regular expression for digits, decimals, and fractions数字、小数和分数的正则表达式
【发布时间】:2021-08-04 23:05:47
【问题描述】:

如何创建一个允许整数、小数、分数和带小数的分数的正则表达式? 字符串也可以有可选文本,仅在末尾。 到目前为止,我有这个:

const re = /^\d*\.?\d*\/?\d*\.?\d*[a-z]*$/gi;

这允许整数中有两位小数(即:'23.23.23'),这是我不想要的。我可以修改此正则表达式以仅在用“/”分隔时允许两个小数点吗?

下面是一些可以通过的例子:

  • 23.23/100公里
  • 1/3
  • .23km
  • 1.mi
  • 1.2/2.1kg

一些不该通过的例子:

  • 1a3km
  • 12.12.12
  • 1.2.3/12.13km
  • 12km/12.44km

【问题讨论】:

  • 您是否应该在数字和单位之间允许空格,以防数据符合 SI 使用空格的方式?

标签: javascript regex


【解决方案1】:

使用

^(?!.*\d+(?:\.\d+){2})\d*\.?\d*\/?\d*\.?\d*[a-z]*$

proof。由于(?!.*\d+(?:\.\d+){2}) 负前瞻,此表达式不允许三个数字之间有句点。

解释

--------------------------------------------------------------------------------
  ^                        the beginning of the string
--------------------------------------------------------------------------------
  (?!                      look ahead to see if there is not:
--------------------------------------------------------------------------------
    .*                       any character except \n (0 or more times
                             (matching the most amount possible))
--------------------------------------------------------------------------------
    \d+                      digits (0-9) (1 or more times (matching
                             the most amount possible))
--------------------------------------------------------------------------------
    (?:                      group, but do not capture (2 times):
--------------------------------------------------------------------------------
      \.                       '.'
--------------------------------------------------------------------------------
      \d+                      digits (0-9) (1 or more times
                               (matching the most amount possible))
--------------------------------------------------------------------------------
    ){2}                     end of grouping
--------------------------------------------------------------------------------
  )                        end of look-ahead
--------------------------------------------------------------------------------
  \d*                      digits (0-9) (0 or more times (matching
                           the most amount possible))
--------------------------------------------------------------------------------
  \.?                      '.' (optional (matching the most amount
                           possible))
--------------------------------------------------------------------------------
  \d*                      digits (0-9) (0 or more times (matching
                           the most amount possible))
--------------------------------------------------------------------------------
  \/?                      '/' (optional (matching the most amount
                           possible))
--------------------------------------------------------------------------------
  \d*                      digits (0-9) (0 or more times (matching
                           the most amount possible))
--------------------------------------------------------------------------------
  \.?                      '.' (optional (matching the most amount
                           possible))
--------------------------------------------------------------------------------
  \d*                      digits (0-9) (0 or more times (matching
                           the most amount possible))
--------------------------------------------------------------------------------
  [a-z]*                   any character of: 'a' to 'z' (0 or more
                           times (matching the most amount possible))
--------------------------------------------------------------------------------
  $                        before an optional \n, and the end of the
                           string

【讨论】:

  • 解释上说?是“(可选(匹配尽可能多的数量))”,但实际上是“0或1次”。
  • @AndrewMorton ? 是一个贪婪的量词。它确实匹配“尽可能多的”。 1 或 0 次。不是0次或1次。 ?? 是惰性的,它匹配“0 或 1 次”。
  • 此解决方案确实有效,谢谢!我尝试使用前瞻方法,尽管我使用的是正向前瞻并且不适合它。
  • @RyszardCzech 请参阅MDN documentation for quantifiers
  • 我想知道这是否只是语言问题。我可以看到有人可以说这对\.? 是正确的:“(可选(匹配尽可能多的数量))”,但对于以英语为母语的人来说,这很令人困惑。类似这样的内容可能更清楚:“如果有一个 . 可用,则匹配一个 .,如果没有,则不匹配。”
【解决方案2】:

这应该可以工作

^[0-9]*(?:\.[0-9]*)?(?:\/[0-9]*(?:\.[0-9]*)?)?[a-zA-Z]*$

【讨论】:

    【解决方案3】:

    您尝试的模式由所有可选部分组成,因为所有量词要么是? 可选,要么是* 0 次或更多次。由于/ 也是可选的,您将匹配12.12.12

    您可以将带有/ 部分的部分设为可选,而无需将/ 本身设为可选。

    如果您想匹配至少一个数字并阻止匹配空字符串,您可以使用正向前瞻来匹配至少一个数字。

    ^(?=[^\d\r\n]*\d)\d*\.?\d*(?:\/\d*\.?\d*)?[a-z]*$
    

    Regex demo

    模式匹配

    • ^ 字符串开始
    • (?=[^\d\r\n]*\d) 断言至少一个数字
    • \d*\.?\d* 匹配可选数字和.
    • (?:非捕获组
      • \/\d*\.?\d* 匹配 / 和可选数字和 .
    • )?关闭非捕获组并使其可选
    • [a-z]* 可选匹配字符 a-z
    • $ 字符串结束

    如果/ 的每一侧至少有一个数字不匹配,例如./.

    ^(?:\d*\.?\d+|\d+\.)(?:\/\d*\.?\d+|\d+\.)?[a-z]*$
    

    模式匹配

    • ^ 字符串开始
    • (?:\d*\.?\d+|\d+\.) 匹配可选数字、可选 . 和 1+ 数字或匹配 1+ 数字和 .
    • (?:非捕获组
      • \/\d*\.?\d+|\d+\. 匹配 / 并再次与第一个模式相同
    • )?关闭非捕获组并使其可选
    • [a-z]* 可选匹配字符 a-z
    • $字符串结束

    Regex demo

    【讨论】:

      猜你喜欢
      • 2012-06-10
      • 1970-01-01
      • 2014-09-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-07-20
      相关资源
      最近更新 更多