【问题标题】:Python - Creating multiple optional groups in regexPython - 在正则表达式中创建多个可选组
【发布时间】:2020-08-07 10:18:22
【问题描述】:

我有两个字符串,其中部分字符串是可选的。因此,我尝试通过在我想要设为可选的每个组之后使用 ? 来创建可选模式。但是,它将None 作为这些组的输出。

Text-1:

text1 = '95031B2\tR\tC01 N1 P93 R-- 12:39:18.540 08/05/20 0000002802 R  -                               No_barcode  FLC   F  LR    7.673353 sccm   Pt   25.288202 psig   FL  536.651917 sccm   EDC   0.000000 sccm   PQ    7.668324 sccm   QF  536.289246 sccm   QP   25.287605 psig   LLQ  -0.109524 sccm   HLQ   4.440174 sccm   CLF   1.429953 sccm   MF    0.000000 sccm   LF  100.000015 sccm   MQF   0.000000 sccm   LQF 100.000015 sccm   FPR  25.290846 psig \r\n'

文本 2:

text2 = '5102060\tR\tC01 N1 P93 R-- 12:38:52.140 08/05/20 0000002801 FO -                               No_barcode \r\n'

text1 的工作模式:

pattern1 = ['(?P<time>\d\d:\d\d:\d\d.\d{3})\s',
           '(?P<date>\d\d/\d\d/\d\d)\s',
           '(?P<sno>\d{10})\s',
           '(?P<status>\w{1,2}).*?-',
           '\s*',
           '(?P<bcode>No_barcode|\W{20})',
           '\s{2}',
           '(?P<type>\w{3})',
           '.*?',
           '(?P<pr>Pt.*?\d*[.]?\d*\s[a-z]+)'
           '\s{1,3}',
           '(?P<fl>FL.*?\d*[.]?\d*\s[a-z]+)'
           ]

试图使上述模式中的可选部分与两个字符串一起工作:

>>> pattern2 = ['(?P<time>\d\d:\d\d:\d\d.\d{3})\s', # time pattern
           '(?P<date>\d\d/\d\d/\d\d)\s',           # date pattern
           '(?P<sno>\d{10})\s',                    # 10 digits
           '(?P<status>\w{1,2}).*?-',              # 1 or 2 alphabets follows with anything and then hyphen('-')
           '\s*',                                  # zero or more spaces
           '(?P<bcode>No_barcode|\W{20})',         # No_barcode or any alphanumeric with 20 length
                                       
                     # OPTIONAL PART STARTS (Not working)
           '(\s{1,2}|',                            # 1 or 2 spaces or
           '(?P<type>\w{3})|',                     # 3 alphabets or
           '.*?|',                                 # anything getting ignored or
           '(?P<pr>Pt.*?\d*[.]?\d*\s[a-z]+)|'      # Pt digits optional decimal followed with digits, 1 space, 1 or more a-z alphabets or
           '\s{1,3}|',                             # 1 to 3 spaces or
           '(?P<fl>FL.*?\d*[.]?\d*\s[a-z]+))?'     # FL digits optional decimal followed with digits, 1 space, 1 or more a-z alphabets 
           ]

输出:

>>> res = re.search(r''.join(pattern1), text) # pattern1
>>> res.groups()
('12:39:18.540', '08/05/20', '0000002802', 'R', 'No_barcode', 'FLC', 'Pt   25.288202 psig', 'FL  536.651917 sccm')

>>> res = re.search(r''.join(pattern2), text) # pattern2, trying to get same output as pattern1
>>> res.groups()
('12:39:18.540', '08/05/20', '0000002802', 'R', 'No_barcode', '  ', None, None, None)

预期输出:

对于模式2(在模式1中添加可选部分后),我应该得到与模式1相同的输出。

>>> res = re.search(r''.join(pattern2), text) # pattern2
>>> res.groups()
('12:39:18.540', '08/05/20', '0000002802', 'R', 'No_barcode', 'FLC', 'Pt   25.288202 psig', 'FL  536.651917 sccm')

【问题讨论】:

  • 您能否具体说明您的目标是什么以及您期望的输出是什么?
  • @tomanizer 我已经添加了有问题的预期输出细节。
  • 你用一个可选的组包裹了强制性部分之后的所有部分,并在模式的每一行之间插入了|交替运算符,这是错误的。如果这些部分都是可选的,则需要用一个可选组包装每个部分。
  • 谢谢。我在模式 2 中的模式 2 中没有看到任何 FL、Pt。您为什么希望它出现在正则表达式中?
  • 您没有正确创建可选组。此外,您应该指定后续子模式是否匹配取决于是否找到前面的子模式。

标签: python regex


【解决方案1】:

您使用可选组将所有部分包装在强制部分之后,并在模式的每一行之间插入| 交替运算符,这是创建可选组的错误方法。

如果部分都是可选的,并且后续的子模式不依赖于是否找到前面的子模式,您需要使用可选组包装每个部分:&lt;obligatory_part&gt;(?:...(optional_1)...)?(?:...(optional_2)...)?(?:...(optional_n)...)?

或者,如果缺少前面的子模式,则如果每个后续模式都无法出现,则创建嵌套的可选组:&lt;obligatory_part&gt;(?:...(optional_1)...(?:...(optional_2)...(?:...(optional_n)...)?)?)?

所以,你可以使用this regex:

(?P<time>\d\d:\d\d:\d\d.\d{3})\s(?P<date>\d\d/\d\d/\d\d)\s(?P<sno>\d{10})\s(?P<status>\w{1,2}).*?-\s*(?P<bcode>No_barcode|\W{20})(?:\s+(?P<type>\w{3}))?(?:.*?(?P<pr>Pt.*?\d*[.]?\d*\s[a-z]+))?(?:\s{1,3}(?P<fl>FL.*?\d*[.]?\d*\s[a-z]+))?

this regex:

(?P<time>\d\d:\d\d:\d\d.\d{3})\s(?P<date>\d\d/\d\d/\d\d)\s(?P<sno>\d{10})\s(?P<status>\w{1,2}).*?-\s*(?P<bcode>No_barcode|\W{20})(?:\s+(?P<type>\w{3})(?:.*?(?P<pr>Pt.*?\d*[.]?\d*\s[a-z]+)(?:\s{1,3}(?P<fl>FL.*?\d*[.]?\d*\s[a-z]+))?)?)?

既然你说你需要Scheme 1,你可以使用

pattern = [r'(?P<time>\d\d:\d\d:\d\d.\d{3})\s',
           r'(?P<date>\d\d/\d\d/\d\d)\s',
           r'(?P<sno>\d{10})\s',
           r'(?P<status>\w{1,2}).*?-',
           r'\s*',
           r'(?P<bcode>No_barcode|\W{20})',
           r'(?:\s+',                     # (?: starts a non-capturing group...
           r'(?P<type>\w{3}))?',          # ...)? closes the group, 
           r'(?:.*?',
           r'(?P<pr>Pt.*?\d*[.]?\d*\s[a-z]+))?'
           r'(?:\s{1,3}',
           r'(?P<fl>FL.*?\d*[.]?\d*\s[a-z]+))?'
          ]
print(r''.join(pattern))

Python demo

【讨论】:

  • 告诉我你需要实现哪个可选方案,我会添加Python代码。
  • 我想使用第一个正则表达式,不需要嵌套可选组,但感谢分享。这很有帮助。 :)
  • @shaikmoed 我添加了 Scheme 1 模式定义。顺便说一句,我建议使用原始字符串文字来避免反斜杠的任何问题。
  • 我不明白每个可选组中使用的非捕获组的目的。不仅关于这个例子,而且我还阅读了其他例子。你能用现在的例子解释一下吗?
  • @shaikmoed 非捕获组用作模式序列的容器,而不会将匹配项存储在单独的内存插槽中。由于您只依赖命名组,因此您可能会使用捕获组,但使用非捕获组在计算上更整洁。另请参阅Are non-capturing groups redundant?
猜你喜欢
  • 1970-01-01
  • 2017-06-21
  • 2022-12-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-04
  • 2013-09-09
相关资源
最近更新 更多