你没有得到匹配的原因是你的正则表达式不匹配:
r"<([A-Za-z0-9_]+)>" 缺少逗号、引号和空格字符,根据您的示例,这些都可能出现在 < > 内。
这个匹配:
re.search(r"< ([A-Za-z0-9_.,\"' ]+) >", txt)
还有一点可能让您感到困惑的是,名称列表是用逗号分隔的,它本身可以是 values 的一部分,未转义。
这意味着您不能只用',' 拆分该字符串,而是需要考虑两个不同的引号字符(' 和")来分隔字段。
所以我会使用这种方法:
- 使用
re.match 将字符串拆分为PREFIX 部分,并丢弃其余部分。
- 使用
re.findall()根据引号将名称拆分为字段
编辑:
1)根据您的第一条评论,您的数据还可以在包含换行符的前缀之前包含一个序言。 . 的默认行为是 to match everything except newlines。
来自 Python re 文档:
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