Python - 在正则表达式中创建多个可选分组

3
我有两个字符串,其中一部分是可选的。因此,我尝试通过在每个要可选的组后面使用“?”来创建可选模式。但是,对于这些组,它会输出“None”。
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'

对不起,我只能使用英文回答您的问题。
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)

预期输出:

对于pattern2(在pattern1中添加一个可选部分后),我应该获得与pattern1相同的输出。

>>> 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
@tomanizer,我在问题中添加了预期输出细节。 - shaik moeed
你把必选部分后面的所有内容都用一个可选组包裹起来,并在模式中每行之间插入了 | 替换运算符,这是错误的。如果所有部分都是可选的,则需要将每个部分都包装在一个可选组中。 - Wiktor Stribiżew
@WiktorStribiżew 我尝试为每个组添加可选运算符。但它并没有按预期工作。您能否将正则表达式发布为答案? - shaik moeed
1
你没有正确创建可选组。此外,你应该指定后续子模式的匹配取决于先前的子模式是否被找到。 - Wiktor Stribiżew
显示剩余2条评论
1个回答

1

你将必选部分后面的所有内容都用一个可选组包裹起来,并在模式中的每一行之间插入了 | 交替运算符,这是一种错误的制作可选组的方式。

如果所有部分都是可选的,且后续子模式不依赖于前面的子模式是否被找到,那么你需要将每个部分都用一个可选组包装起来:<obligatory_part>(?:...(optional_1)...)?(?:...(optional_2)...)?(?:...(optional_n)...)?

或者,如果每个后续模式在前面的子模式缺失时都不能出现,那么可以制作嵌套的可选组:<obligatory_part>(?:...(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演示


请告诉我您需要实现哪个可选方案,我会添加Python代码。 - Wiktor Stribiżew
我想使用第一个正则表达式,嵌套的可选组不是必需的,但感谢分享。这很有帮助。 :) - shaik moeed
1
@shaikmoeed 我添加了 Scheme 1 模式定义。顺便建议使用原始字符串字面量,以避免反斜杠引起的任何问题。 - Wiktor Stribiżew
@shaikmoeed 非捕获组用作模式序列的容器,而不将匹配结果存储在单独的内存槽中。由于您只依赖于命名组,因此可以使用捕获组,但使用非捕获组更加简洁。另外,请参阅非捕获组是否多余? - Wiktor Stribiżew
我尝试只添加可选组并删除非捕获组,但没有成功。你知道原因吗? - shaik moeed
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接