Python 在逗号处拆分字符串,括号环境中除外
我希望将Python多行字符串拆分为逗号,除非逗号位于括号内的表达式中。例如,绳子Python 在逗号处拆分字符串,括号环境中除外,python,regex,parsing,pyparsing,Python,Regex,Parsing,Pyparsing,我希望将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.'] 这涉及到括号匹配,所以正则表达式在这里可能没有帮助。除了引号(“)环境受到保护而不是{}分隔的环境之外,它几乎满足了我的需要 有什
{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.']
这涉及到括号匹配,所以正则表达式在这里可能没有帮助。除了引号(“
)环境受到保护而不是{}
分隔的环境之外,它几乎满足了我的需要
有什么提示吗?编写自己的自定义拆分函数:
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
在这种情况下,您可以使用:
>>> 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
实际上可以在Python中使用(我刚刚用一个编号的组替换了命名组以使其更短):
AFAIK Python不支持正则表达式中的递归。仅供参考,这将与PCRE一起使用:
(?'brages'\{(?:[^{}]++\g)*\})(*SKIP)(*FAIL)|,
这不是一件小事,你会问……正则表达式没有帮助,因为你需要一个带内存的状态机来匹配封闭项……(brakset、引号等)如果没有递归正则表达式(执行递归的正则表达式),这是不可能的。我认为Python现在有了一个更新的版本来实现这一点。有趣的是,Perl是如何从Python来的,Perl却把它抛在了身后。@sln:What does“Perl是如何从Python来的“什么意思?Perl在Guido开始考虑Python时就已经存在了,在大多数人听说Python之前就已经广泛使用,并且在1.x/2.x早期对Python的开发产生了影响。尤其是Python的re
引擎直接基于Perl。我不确定能够在没有警告的情况下在regexp上花费指数级的时间是否算作“把它扔在尘土里”…@abarnert-我认为Perl可能已经存在,但Perl采用了很多功能,这是我不知道的第一个。我想我读了一些关于Python re beta站点的详细信息,似乎在使用可用的语法构造方面有了很多新的东西这是当前唯一正确的答案,但此实现的假设是字符串中没有可能不属于分组的“{”或“}”字符。i、 e.“:-}”如果这种可能性曾经存在,那么就需要考虑如何处理它。对于更为复杂的嵌套括号示例,这不会失败吗?例如,“{J.Doe,R.Starr{x,{y}}},{Lorem{i}psum dolor},Dol.sit.,am.et.”
?@ajcr-是的,它会失败。但这就是为什么我说“在这种情况下”。我给出的模式不是防弹的,只能处理简单的字符串。具体来说,它用于没有带逗号的嵌套大括号的字符串,如OP的示例中所示。但是,如果OP处理的字符串如此复杂,最好抛弃正则表达式,转而构建解析器。我认为你不能将其概括为任何级别的解决方案。如果你愿意接受一种无法处理更复杂情况的快速破解方法,为什么不采用最简单的方法呢?你真的不需要处理成对的开括号和闭括号;只需将开放大括号和闭合大括号视为等效的可选“quote”字符,并跳过“quotes”中的任何逗号,就像PyParsing或csv
或其他类似操作一样?
>>> 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.']
>>> print([x for x in r.split(s) if x])
['{J. Doe, R. Starr}', '{Lorem\n{i}psum dolor }', 'Dol. sit.', 'am. et.']