1

给定这样的字符串:

ORTH < "cali.ber,kl", 'calf' , "done" >,\nLKEYS.KEYREL.PRED "_calf_n_1_rel", 

使用正则表达式,我如何获得如下所示的元组:

('ORTH', ['cali.ber,kl','calf','done'])

我一直在这样做:

txt = '''ORTH < "cali.ber,kl", 'calf' , "done" >,'''
e1 = txt.partition(" ")[0]
vs = re.search(r"<([A-Za-z0-9_]+)>", txt)
v = vs.group(1)
v1 = [i[1:-1] for i in vs.strip().strip("<>").split(",")]
print v1

但我没有得到re.search().group(1)。应该怎么做才能得到想要的输出?

4

1 回答 1

2

你没有得到匹配的原因是你的正则表达式不匹配:

r"<([A-Za-z0-9_]+)>"缺少逗号、引号和空格字符,< >根据您的示例,它们都可能出现在 内部。

这个匹配:

re.search(r"< ([A-Za-z0-9_.,\"' ]+) >", txt)

还可能使您感到困惑的是,名称列表由逗号分隔,它本身可以是未转义的values的一部分。

这意味着您不能只将该字符串拆分为',',而是需要考虑两个不同的引号字符('")以分隔字段。

所以我会使用这种方法:

  • 用于re.match将字符串拆分为 PREFIX < NAMES > 部分,并丢弃其余部分。
  • 用于re.findall()根据引号将名称拆分为字段

编辑:

1)根据您的第一条评论,您的数据还可以在包含换行符的前缀之前包含一个序言。的默认行为.匹配除换行符以外的所有内容。

来自 Pythonre文档:

re.DOTALL

使'.'特殊字符完全匹配任何字符,包括换行符;没有这个标志,'.'将匹配除换行符以外的任何内容。

所以你需要用re.DOTALL标志构造那个正则表达式。您可以通过首先编译它并传递ORed 标志来做到这一点:

re.compile(pattern, flags=re.DOTALL)

2)如果您之前PREFIX在正则表达式中包含空格字符,它只会匹配实际包含该空格的数据 - 但不再匹配您的第一条示例数据。所以我.*?([A-Z\.]*)...用来涵盖这两种情况。?用于非贪婪匹配,因此它匹配最短的匹配而不是最长的匹配。

3)通过包含字符并转义它来覆盖PREFIX.FOO只是扩展前缀的模式。([A-Z\.]*).

更新的示例涵盖了您提到的所有案例:

import re

TEST_VALUES = [
    """ORTH.FOO < "cali.ber,kl", 'calf' , "done" >,\nLKEYS.KEYREL.PRED "_calf_n_1_rel",""",
    """calf_n1 := n_-_c_le & n_-_pn_le &\n [ ORTH.FOO < "cali.ber,kl", 'calf' , "done" >,\nLKEYS.KEYREL.PRED "_calf_n_1_rel","""
]

EXPECTED = ('ORTH.FOO', ['cali.ber,kl','calf','done'])


pattern = re.compile(r'.*?([A-Z\.]*) < (.*) >.*', flags=re.DOTALL)


for value in TEST_VALUES:
    prefix, names_str = pattern.match(value).groups()
    names = re.findall('[\'"](.*?)["\']', names_str)

    result = prefix, names
    assert(result == EXPECTED)

print result
于 2013-08-06T17:46:16.940 回答