【问题标题】:Conditional(?) regex for numbers数字的条件(?)正则表达式
【发布时间】:2021-11-29 17:14:11
【问题描述】:

我试图创建一个可以匹配括号内数字的正则表达式,例如:

(1.000.000,00) //match
(1.000,00)     //match
(100,00)       //match
(10)           //match
(1)            //match

(2.000.000,00  //dont't match
(2.000,00      //dont't match
(200,00        //dont't match
(20            //dont't match
(2             //dont't match

3.000.000,00)  //dont't match
3.000,00)      //dont't match
300,00)        //dont't match
30)            //dont't match
3)             //dont't match

4.000.000,00   //should match
4.000,00       //should match
400,00         //should match
40             //should match
4              //should match

我只需要匹配数字(是否在括号中),但前提是它们包含所有括号 (2) 或没有 (0)

目前这是我想出的:\((\d+[\.,]?)+\d*\),它匹配 --match 而不匹配 --don't match但也应该匹配 --should match

我添加了javascript 标签,因为我在 js 中使用了这个正则表达式,并不是所有的正则表达式标记都可以在 js 正则表达式构造函数中工作

我还发布了一个 regex101 link

【问题讨论】:

    标签: javascript regex


    【解决方案1】:

    如果支持,您可以使用否定的lookbehind 来匹配带括号或不带括号:

    \(\d+(?:[.,]\d+)*\)|(?<!\S)\d+(?:[.,]\d+)*(?!\S)
    
    • \(匹配(
    • \d+(?:[.,]\d+)* 匹配 1+ 位并可选择重复匹配 ., 并再次匹配 1+ 位
    • \) 匹配)
    • |或者
    • (?&lt;!\S) 否定后视,向左断言一个单词边界
    • \d+(?:[.,]\d+)* 匹配 1+ 个数字,并可选择重复匹配 ., 并再次匹配 1+ 个数字
    • (?!\S) 负前瞻,在右侧断言空白边界

    Regex demo

    另一个选项可能是匹配两边的可选括号,并且只保留有左括号和右括号的括号,或者没有。

    const regex = /\(?\d+(?:[.,]?\d+)*\)?/
    const strings = ["(1.000.000,00)", "(1.000,00)", "(100,00)", "(10)", "(1)", "(2.000.000,00", "(2.000,00", "(200,00", "(20", "(2", "3.000.000,00)", "3.000,00)", "300,00)", "30)", "3)", "4.000.000,00", "4.000,00", "400,00", "40", "4"];
    
    strings.forEach(s => {
    
      const m = s.match(regex);
      const firstChar = s.charAt(0);
      const lastChar = s.charAt(s.length - 1);
    
      if (
        m &&
        (firstChar !== '(' && lastChar !== ')') ||
        firstChar === '(' && lastChar === ')'
      ) {
        console.log(s)
      }
    });

    【讨论】:

    • 您的正则表达式有效,我可以要求对此进行简要解释吗?如果您不想担心,我会在 regex101 上观看。但无论如何,这正是它应该匹配的。非常感谢!
    • @Nick 当然,我已经添加了各个部分的细分。
    【解决方案2】:

    如果您不想重复零件匹配编号(在这种情况下很短,因此可能需要对 DRY 规则进行例外处理),您可以联系\(?((\d+[\.,]?)+\d*)\)?(?&lt;=\(\1\)|(^|[^(\d.,])\1(?=($|[^\d.,)])))

    【讨论】:

      【解决方案3】:

      编辑:这是坏的。 它将匹配像 (7 这样的数字,因为它只匹配数字并在这种情况下忽略括号。

      留在这里以备将来参考。

      在多次传递中执行正则表达式通常更容易,但这里是:

      /(\((\d+[\.,]?)+\d*\))|(\d+[\.,]?\d*)/gm
      

      您可以在https://regex101.com/ 上对其进行测试。 通常最好在多次传递中处理某些内容,因为您可以看到正则表达式变得更加不可读。 我把你的正则表达式分成两个正则表达式:一个需要括号,一个不需要括号,然后将它们与 or 运算符结合起来。 请注意,此正则表达式将允许将“123.3,5.7”之类的内容作为一个数字,并且捕获组会很讨厌。

      【讨论】:

      • 由于解释和您花费的时间,我赞成您回答,但是即使只有一个括号(我想避免),您的正则表达式也匹配。最后,我知道它并不完美,但我知道我接收到某种格式的数据,所以像 123.3,5.7 这样的东西是不可能的
      • 没想到哈哈。
      • 我明白了,您要确保在其他情况下没有前置或后置正则表达式。
      猜你喜欢
      • 1970-01-01
      • 2016-09-19
      • 2011-10-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多