繁体   English   中英

以逗号分隔字符串,括号环境中除外

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM