[英]Split string at commas except when in bracket environment
我想在逗号处拆分 Python 多行字符串,除非逗号在括号内。 例如,字符串
{J. Doe, R. Starr}, {Lorem
{i}psum dolor }, Dol. sit., am. et.
应该分成
['{J. Doe, R. Starr}', '{Lorem\n{i}psum dolor }', 'Dol. sit.', 'am. et.']
这涉及括号匹配,所以可能正则表达式在这里没有帮助。 PyParsing有一个commaSeparatedList
,它几乎commaSeparatedList
我的需要,除了引号( "
) 环境受到保护而不是{}
分隔的环境。
任何提示?
编写您自己的自定义拆分函数:
input_string = """{J. Doe, R. Starr}, {Lorem
{i}psum dolor }, Dol. sit., am. et."""
expected = ['{J. Doe, R. Starr}', '{Lorem\n{i}psum dolor }', 'Dol. sit.', 'am. et.']
def split(s):
parts = []
bracket_level = 0
current = []
# trick to remove special-case of trailing chars
for c in (s + ","):
if c == "," and bracket_level == 0:
parts.append("".join(current))
current = []
else:
if c == "{":
bracket_level += 1
elif c == "}":
bracket_level -= 1
current.append(c)
return parts
assert split(input_string), expected
在这种情况下,您可以使用re.split
:
>>> from re import split
>>> data = '''\
... {J. Doe, R. Starr}, {Lorem
... {i}psum dolor }, Dol. sit., am. et.'''
>>> split(',\s*(?![^{}]*\})', data)
['{J. Doe, R. Starr}', '{Lorem\n{i}psum dolor }', 'Dol. sit.', 'am. et.']
>>>
下面是对正则表达式模式匹配内容的解释:
, # Matches ,
\s* # Matches zero or more whitespace characters
(?! # Starts a negative look-ahead assertion
[^{}]* # Matches zero or more characters that are not { or }
\} # Matches }
) # Closes the look-ahead assertion
Lucas Trzesniewski 的评论实际上可以在带有PyPi 正则表达式模块的Python 中使用(我只是用编号替换了命名组以使其更短):
>>> import regex
>>> r = regex.compile(r'({(?:[^{}]++|\g<1>)*})(*SKIP)(*FAIL)|\s*,\s*')
>>> s = """{J. Doe, R. Starr}, {Lorem
{i}psum dolor }, Dol. sit., am. et."""
>>> print(r.split(s))
['{J. Doe, R. Starr}', None, '{Lorem\n{i}psum dolor }', None, 'Dol. sit.', None, 'am. et.']
模式 - ({(?:[^{}]++|\\g<1>)*})(*SKIP)(*FAIL)
- 匹配{...{...{}...}...}
类似结构(作为{
匹配{
, (?:[^{}]++|\\g<1>)*
匹配 0+ 次出现的 2 个替代项:1)除{
和}
之外的任何 1+ 个字符( [^{}]++
), 2) 匹配整个文本({(?:[^{}]++|\\g<1>)*})
子模式)。 (*SKIP)(*FAIL)
动词使引擎忽略匹配缓冲区中的整个匹配值,因此,将索引移动到匹配的末尾并且不保留任何返回值(我们“跳过”匹配的内容)。
\\s*,\\s*
匹配包含 0+ 个空格的逗号。
出现None
值是因为当第二个分支匹配时,第一个分支中有一个捕获组为空。 我们需要在第一个替代分支中使用捕获组进行递归。 要删除空元素,请使用理解:
>>> print([x for x in r.split(s) if x])
['{J. Doe, R. Starr}', '{Lorem\n{i}psum dolor }', 'Dol. sit.', 'am. et.']
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.