如何在Python中拆分但忽略引号中的分隔符?

75 投票
17 回答
81362 浏览
提问于 2025-04-15 22:26

我需要把一个字符串按照分号来分割。但是,我不想分割那些在字符串内部的分号(比如在单引号或双引号里面的)。我不是在解析文件,只是处理一个简单的字符串,没有换行。

part 1;"this is ; part 2;";'this is ; part 3';part 4;this "is ; part" 5

结果应该是:

  • part 1
  • "this is ; part 2;"
  • 'this is ; part 3'
  • part 4
  • this "is ; part" 5

我想这可以用正则表达式来实现,但如果不行,我也愿意尝试其他方法。

17 个回答

24

这段代码是用来做某些操作的,但具体的功能需要根据上下文来理解。一般来说,代码块里面的内容会包含一些指令或者逻辑,用来处理数据或者实现特定的功能。

如果你看到这样的代码块,通常意味着这里有一些重要的代码需要关注。理解这些代码的作用,可以帮助你更好地掌握编程的基本概念。

记住,编程就像是给计算机下指令,代码块就是这些指令的集合。每一行代码都有它的意义,理解它们的作用是学习编程的关键。

>>> a='A,"B,C",D'
>>> a.split(',')
['A', '"B', 'C"', 'D']

It failed. Now try csv module
>>> import csv
>>> from StringIO import StringIO
>>> data = StringIO(a)
>>> data
<StringIO.StringIO instance at 0x107eaa368>
>>> reader = csv.reader(data, delimiter=',') 
>>> for row in reader: print row
... 
['A,"B,C",D']
46
re.split(''';(?=(?:[^'"]|'[^']*'|"[^"]*")*$)''', data)

每当它找到一个分号时,预查看会扫描剩下的整个字符串,确保单引号和双引号的数量都是偶数。(在双引号字段内的单引号,或者在单引号字段内的双引号,会被忽略。)如果预查看成功,那么这个分号就可以作为分隔符。

Duncan的解决方案不同,后者是匹配字段而不是分隔符,这个方法对空字段没有问题。(甚至最后一个字段也不会出问题:与许多其他split实现不同,Python的实现不会自动丢弃末尾的空字段。)

57

大部分的回答看起来都复杂得多。其实你不需要用到回溯引用,也不需要依赖于re.findall是否能找到重叠的匹配项。因为输入数据不能用csv模块来解析,所以用正则表达式几乎是唯一的选择。你只需要用re.split来调用一个匹配字段的模式就可以了。

注意,这里匹配字段比匹配分隔符要简单得多:

import re
data = """part 1;"this is ; part 2;";'this is ; part 3';part 4;this "is ; part" 5"""
PATTERN = re.compile(r'''((?:[^;"']|"[^"]*"|'[^']*')+)''')
print PATTERN.split(data)[1::2]

输出结果是:

['part 1', '"this is ; part 2;"', "'this is ; part 3'", 'part 4', 'this "is ; part" 5']

正如Jean-Luc Nacif Coelho正确指出的,这种方法对空组的处理不太准确。根据具体情况,这可能会有影响,也可能没有。如果有影响,可以尝试通过将';;'替换为';<marker>;'来处理,其中<marker>应该是一个你知道在数据中不会出现的字符串(不能包含分号)。另外,处理完后你还需要恢复数据:

>>> marker = ";!$%^&;"
>>> [r.replace(marker[1:-1],'') for r in PATTERN.split("aaa;;aaa;'b;;b'".replace(';;', marker))[1::2]]
['aaa', '', 'aaa', "'b;;b'"]

不过这只是个权宜之计。有没有更好的建议呢?

撰写回答