【问题标题】:regex matching and all optional groups正则表达式匹配和所有可选组
【发布时间】:2016-04-02 18:38:01
【问题描述】:

当所有组都可能是可选的时,我无法提取组。


上下文(如果喜欢,可以跳到结尾): 这是在将字符串与一组正则表达式进行最佳匹配的上下文中,并查看哪个表达式具有最多的组匹配。

例如,我可能有一种潜在的格式;

1: [A|B] [CD|DE|EF]-[1-1|1-2|2-2|2-3] [G|H]

但我希望用户输入错误,或者不包含空格或其他内容。

所以我可能会针对字符串对其进行测试

A CD-1-1 G

想要组团

  1. 一个
  2. 光盘
  3. 1-1
  4. G

另外,对于测试字符串

DE-1-9 G

我想买

  1. 德国
  2. G

所以这是我的正则表达式来匹配以下可选组

[A|B] [CD|DE|EF]-[1-1|1-2|2-2|2-3] [G|H]

正则表达式:

(A|B)?(?: *)?(CD|DE|EF)?(?:-|(?: ))?((?:1-(?:1|2))|(?:2-(?:2|3)))?(?: *)?(G|H)?

分解我认为这应该如何工作;

  • (A|B)? - 匹配“A”或“B”字符(可能存在也可能不存在)。
  • (?: *)? - 匹配一些空格字符(可能不存在),但不需要组。
  • (CD|DE|EF)? - 匹配“CD”“DE”或“EF”(可能存在也可能不存在)。
  • (?:-|(?: ))? - 匹配一个“-”或一些空格(可能有也可能没有)。
  • ((?:1-(?:1|2))|(?:2-(?:2|3)))? - 匹配 [1-[1|2]] 或 [2-[2|3]](可能不正确/根本不存在)
  • (?: *)? - 匹配一些空格字符(可能不存在),但不需要组。
  • (G|H)? - 匹配“G”或“H”字符(可能存在也可能不存在)。

这个与我期望的组不匹配与测试字符串的问题

A CD 1-9 G

我期待团体

  1. 一个
  2. 光盘
  3. G

但我明白了

  1. 一个
  2. 光盘

为什么在第三组之后不匹配?

【问题讨论】:

  • 我认为 Wiktor 的模式有效,为了回答您的问题,[1-1|1-2|2-2|2-3] 是可选的,但是只有在它的位置没有任何内容时,`G` 才会匹配。 1-9 打破了这种模式。 Wiktor 通过在每个中心模式中允许一个空的替代方案来解决这个问题。

标签: regex


【解决方案1】:

我建议使用

^([AB]?) *(?:(CD|DE|EF)?|[^- ]*)[- ]?(?:(1-[12]|2-[23])?|\S*) *([GH]?)$

regex demo

当然,重点是添加 $ 锚 - 字符串结尾断言,使字符串匹配到其结尾。

接下来,正如Paulo Almeida 指出的in the comment,如果没有1-1,则必须有一些其他的子模式来匹配,例如1-9。因为在CD / DE / EF 之后可以是连字符或空格,所以让我们将除空格或- 之外的0+ 个字符与[^ - ] 匹配。因为在1-1 / 1-2 / 2-2 / 2-3 之后可以有一个空格,让我们匹配所有非空格字符。可以有更多这样的调整,但这就是可以编写工作正则表达式的方式。

我还建议摆脱单个字符的交替并将它们转换为字符类。 (?: *)? = *.

【讨论】:

    【解决方案2】:

    Regex101 在匹配 2 中捕获 G。尝试添加 global 修饰符。

    【讨论】:

      【解决方案3】:

      这看起来有点像验证,几乎所有内容都是可选的。
      尽管如此,你还是需要一些东西来帮助排好队。

      首先,锚定^$。需要这个或其他一些伪锚(文本)
      给它一个开始和结束来集中搜索。

      其次,数据部分之间常用的可选分隔符。这给了
      它可以消费。可以使用空格和破折号[- ]

      这将使零件从左到右排列。它们都是可选的。

      ^(?=.)[- ]*([AB])?[- ]*(CD|DE|EF)?[- ]*(?:(1-[12]|2-[23])|\d-\d)?[- ]*([GH])?[- ]*$

      一些解释:

       ^                             # Beginning of string
       (?= . )                       # Only used to insure not a blank line
       [- ]*                         # Optional specific delimiters
       ( [AB] )?                     # (1), Optional A or B
       [- ]*                         # Optional specific delimiters
       ( CD | DE | EF )?             # (2), Optional CD or DE or EF
       [- ]*                         # Optional specific delimiters
       (?:                           # Optional numb-numb
            ( 1- [12] | 2- [23] )         # (3), Only ones we care about
         |                              # or,
            \d - \d                       # Any numb-numb
       )?
       [- ]*                         # Optional specific delimiters
       ( [GH] )?                     # (4), Optional G or H
       [- ]*                         # Optional specific delimiters
       $                             # End of string
      

      所有捕获组都设置为可选(不是它们的内容),所以它使得
      很容易测试它们是否有数据(NULL 或长度>0,具体取决于引擎)。

      测试:

      为了测试,我使用了多行模式,并将所有条目作为一个单独的
      字符串(如果您一次只检查一个输入,请不要使用此模式)。

      输入:

      A CD 1-9 G
      DE-1-9 G
      A CD-1-1 G
      AG
      4-8
      

      输出:

       **  Grp 0 -  ( pos 0 , len 10 ) 
      A CD 1-9 G  
       **  Grp 1 -  ( pos 0 , len 1 ) 
      A  
       **  Grp 2 -  ( pos 2 , len 2 ) 
      CD  
       **  Grp 3 -  NULL 
       **  Grp 4 -  ( pos 9 , len 1 ) 
      G  
      -----------
       **  Grp 0 -  ( pos 12 , len 8 ) 
      DE-1-9 G  
       **  Grp 1 -  NULL 
       **  Grp 2 -  ( pos 12 , len 2 ) 
      DE  
       **  Grp 3 -  NULL 
       **  Grp 4 -  ( pos 19 , len 1 ) 
      G  
      -----------
       **  Grp 0 -  ( pos 22 , len 10 ) 
      A CD-1-1 G  
       **  Grp 1 -  ( pos 22 , len 1 ) 
      A  
       **  Grp 2 -  ( pos 24 , len 2 ) 
      CD  
       **  Grp 3 -  ( pos 27 , len 3 ) 
      1-1  
       **  Grp 4 -  ( pos 31 , len 1 ) 
      G  
      -----------
       **  Grp 0 -  ( pos 34 , len 2 ) 
      AG  
       **  Grp 1 -  ( pos 34 , len 1 ) 
      A  
       **  Grp 2 -  NULL 
       **  Grp 3 -  NULL 
       **  Grp 4 -  ( pos 35 , len 1 ) 
      G  
      -----------
       **  Grp 0 -  ( pos 38 , len 3 ) 
      4-8  
       **  Grp 1 -  NULL 
       **  Grp 2 -  NULL 
       **  Grp 3 -  NULL 
       **  Grp 4 -  NULL 
      

      【讨论】:

      • 又一个很好的答案。感谢您浏览它。
      • @THRND - 没问题。这是一个 20 美元的答案,因为它提供了一种可以垂直应用的技术。快速 2 美元的答案就像一次性的,使用一次就不能再使用了..
      猜你喜欢
      • 2020-06-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-06-06
      • 1970-01-01
      • 1970-01-01
      • 2016-05-02
      相关资源
      最近更新 更多