4

我正在尝试使用 Pythons re -module 匹配一些字符串,但无法正确完成。我要处理的字符串如下所示(示例)

XY_efgh_1234_0040_rev_2_1_NC_asdf
XY_abcd_1122Ae_1150_rev2_1_NC
XY_efgh_0124e_50_NC
asdf_1980_2234a_2
XY_abcd_5098_2270_2_1_NC
PC_bos_7659Ae_1450sp_rev_2_1_NC_GRAPH

那里的模式不是恒定的,它可能会有所不同。这对我很重要:

  • 忘记字符串的开头,直到第一个数值。那不重要,我不需要这个,应该从任何结果中删除它。

  • 然后总是有四个数字,它们后面可以跟字母字符(最多三个)。我需要这部分,提取。

  • 然后,在一些下划线之后(其中也可能有一个减号),是我需要的另一组数值,它始终是2 到 4 (......并且后面也可能最多跟三个字母字符)

  • 在本节之后,由下划线分隔,可能还有其他重要的数值,属于以前的值。里面可能还有字母字符...

  • 字符串的结尾可能包含诸如“NC”之类的内容,也可能包含更多字符,这并不重要,应该被删除。

所以,根据前面的例子,这就是我需要处理的:

('1234',   '0040_rev_2_1')
('1122Ae', '1150_rev2_1')
('0124e',  '50')
('1980',   '2234a_2')
('5098',   '2270_2_1')
('7659Ae', '1450sp_rev_2_1')

...我从来没有在 RegEx 中做过这样的 if-and-ifnot事情,这让我发疯。这是我到目前为止所得到的,但这并不是我所需要的:

pattern     = re.compile(
              r"""
              ([0-9]{4}
              [A-Z]{0,3})
              [_-]{1,3}
              ([0-9]{2,4}
              [0-9A-Z_-]{0,16})
              """,
              re.IGNORECASE | 
              re.VERBOSE
              )

if re.search(pattern, string):
    print re.findall(pattern, string)

当我在最后提到的示例中使用它时,这就是我得到的:

[(u'7659Ae', u'1450sp_rev_2_1_NC_GR')]

...几乎是我需要的——但我不知道最后如何排除这个_NC_GR,而且这种通过计数限制字符的简单方法并不好。

有没有人对此案有一个很好且可行的解决方案?

4

2 回答 2

3

您需要使用否定前瞻来匹配后面没有NC. 的字符。重新格式化您的正则表达式以显示分组:

pattern     = re.compile(r"""
              ( [0-9]{4} [A-Z]{0,3} )
              [_-]{1,3}
              ( [0-9]{2,4} (?:[0-9A-Z_-](?!NC))* )
              """, re.IGNORECASE | re.VERBOSE)

{0,16}粗体*量词替换,结果:

>>> for match in pattern.findall(inputtext):
...     print match
... 
('1234', '0040_rev_2_1')
('1122Ae', '1150_rev2_1')
('0124e', '50')
('1980', '2234a_2')
('5098', '2270_2_1')
('7659Ae', '1450sp_rev_2_1')

所以(非捕获)组(?:[0-9A-Z_-](?!NC))匹配任何数字、字母、下划线或破折号后面没有字符的NC

于 2013-03-19T19:17:37.020 回答
2

对我来说,Martijn 的解决方案不起作用。所以我给出我的解决方案。

注意我不使用的事实re.IGNORECASE
因此,我的正则表达式能够赶上
PC_bos_7659Ae_1450sp_rev_2_1_nc_woof
我不知道在这种情况下是否真的是你想要的

inputtext = """XY_efgh_1234_0040_rev_2_1_NC_asdf
XY_abcd_1122Ae_1150_rev2_1_NC
XY_efgh_0124e_50_NC
asdf_1980_2234a_2
XY_abcd_5098_2270_2_1_NC
PC_bos_7659Ae_1450sp_rev_2_1_NC_GRAPH
PC_bos_7659Ae_1450sp_rev_2_1_nc_woof"""
print inputtext

.

import re

print """\n----------------------------------------
WANTED
('1234',   '0040_rev_2_1')
('1122Ae', '1150_rev2_1')
('0124e',  '50')
('1980',   '2234a_2')
('5098',   '2270_2_1')
('7659Ae', '1450sp_rev_2_1')"""
print '----------- eyquem ----------------------'
ri = re.compile('^\D+'
                '(\d{4}[a-zA-Z]{0,3})'
                '[_-]+'
                '(.+?)'
                '(?:[_-]+NC.*)?$',
                re.MULTILINE)

for match in ri.findall(inputtext):
    print match
    
print '----------- Martijn ----------------------'
ro     = re.compile(
              r"""
              ([0-9]{4}
              [A-Z]{0,3})
              [_-]{1,3}
              ([0-9]{2,4}
              [0-9A-Z_-]{0,16}?)
              (?:[-_]NC)?
              """,
              re.IGNORECASE | re.VERBOSE)

for match in ro.findall(inputtext):
    print match

结果

----------------------------------------
WANTED
('1234',   '0040_rev_2_1')
('1122Ae', '1150_rev2_1')
('0124e',  '50')
('1980',   '2234a_2')
('5098',   '2270_2_1')
('7659Ae', '1450sp_rev_2_1')
----------- eyquem ----------------------
('1234', '0040_rev_2_1')
('1122Ae', '1150_rev2_1')
('0124e', '50')
('1980', '2234a_2')
('5098', '2270_2_1')
('7659Ae', '1450sp_rev_2_1')
('7659Ae', '1450sp_rev_2_1_nc_woof')
----------- Martijn ----------------------
('1234', '0040')
('1122Ae', '1150')
('0124e', '50')
('1980', '2234')
('5098', '2270')
('7659Ae', '1450')
('7659Ae', '1450')

我的正则表达式可用于单独的行::

for s in inputtext.splitlines(True):
    print ri.match(s).groups()

相同的结果

.

编辑

import re

inputtext = """XY_efgh_1234_0040_rev_2_1_NC_asdf
XY_abcd_1122Ae_1150_rev2_1_NC
XY_efgh_0124e_50_NC
XY_efgh_0228e_66-__NC
asdf_1980_2234a_2   
asdf_2999_133a
XY_abcd_5098_2270_2_1_NC
XY_abcd_6099_33370_2_1_NC
XY_abcd_6099_3370abcd_2_1_NC
PC_bos_7659Ae_1450sp_rev_2_1_NC_GRAPH
PC_bos_7659Ae_1450sp_rev_2_1___NC_GRAPH
PC_bos_7659Ae_1450sp_rev_2_1_nc_woof_NC
PC_bos_7659Ae_1450sp_rev_2_1_anc_woof_NC
PC_bos_7659Ae_1450sp_rev_2_1_abNC_woof_NC"""

print '----------- Martijn 2 ------------'
ruu     = re.compile(r"""
              ( [0-9]{4} [A-Z]{0,3} )
              [_-]{1,3}
              ( [0-9]{2,4} (?:[0-9A-Z_-](?!NC))* )
              """, re.IGNORECASE | re.VERBOSE)
for match in ruu.findall(inputtext):
    print match
print '----------- eyquem 2 ------------'
rii = re.compile('[_-]'
                '(\d{4}[A-Z]{0,3})'
                '[_-]{1,3}'
                '('
                  '(?=\d{2,4}[A-Z]{0,3}(?![\dA-Z]))'
                  '(?:[0-9A-Z_-]+?)'
                 ')'
                '(?:[-_]+NC.*)?'
                '(?![0-9A-Z_-])',
                re.IGNORECASE)
for m in rii.findall(inputtext):
    print m

结果

----------- Martijn 2 ------------
('1234', '0040_rev_2_1')
('1122Ae', '1150_rev2_1')
('0124e', '50')
('0228e', '66-_')
('1980', '2234a_2')
('2999', '133a')
('5098', '2270_2_1')
('6099', '33370_2_1')
('6099', '3370abcd_2_1')
('7659Ae', '1450sp_rev_2_1')
('7659Ae', '1450sp_rev_2_1__')
('7659Ae', '1450sp_rev_2_1')
('7659Ae', '1450sp_rev_2_1_')
('7659Ae', '1450sp_rev_2_1_a')
----------- eyquem 2 ------------
('1234', '0040_rev_2_1')
('1122Ae', '1150_rev2_1')
('0124e', '50')
('0228e', '66')
('1980', '2234a_2')
('2999', '133a')
('5098', '2270_2_1')
('7659Ae', '1450sp_rev_2_1')
('7659Ae', '1450sp_rev_2_1')
('7659Ae', '1450sp_rev_2_1')
('7659Ae', '1450sp_rev_2_1_anc_woof')
('7659Ae', '1450sp_rev_2_1_abNC_woof')

评论:

  • 我的正则表达式没有捕捉到“33370_2_1”或“3370abcd_2_1”,因为它们不尊重“2 到 4 个字母可能后跟最多 3 个数字”的模式
    ,而 Martijn 的解决方案捕捉到了它们

  • 我的正则表达式捕获的部分的末端是干净的;在 Martijn 的代码中,它们不是

  • Martijn 的正则表达式在每个序列 NC 或 nc 之前停止,即使它前面没有下划线,也就是说,即使这些序列是作为所需部分的一部分的字母。
    如果不需要我的正则表达式的这个特性,对我说,我会修改它

于 2013-03-19T21:10:41.767 回答