我需要使用string.punctuation
和string.whitespace
中的每个字符作为分隔符来拆分数据字符串。
此外,我需要将分隔符保留在输出列表中,在它们在字符串中分隔的项之间。
例如,
"Now is the winter of our discontent"
应输出:
['Now', ' ', 'is', ' ', 'the', ' ', 'winter', ' ', 'of', ' ', 'our', ' ', 'discontent']
我不知道如何在不诉诸嵌套循环的狂欢的情况下如何做到这一点,这是不可接受的慢。我该怎么办?
答案 0 :(得分:21)
与其他人不同的非正则表达式方法:
>>> import string
>>> from itertools import groupby
>>>
>>> special = set(string.punctuation + string.whitespace)
>>> s = "One two three tab\ttabandspace\t end"
>>>
>>> split_combined = [''.join(g) for k, g in groupby(s, lambda c: c in special)]
>>> split_combined
['One', ' ', 'two', ' ', 'three', ' ', 'tab', '\t', 'tabandspace', '\t ', 'end']
>>> split_separated = [''.join(g) for k, g in groupby(s, lambda c: c if c in special else False)]
>>> split_separated
['One', ' ', 'two', ' ', 'three', ' ', 'tab', '\t', 'tabandspace', '\t', ' ', 'end']
我想可以使用dict.fromkeys
和.get
代替lambda
。
[编辑]
一些解释:
groupby
接受两个参数,一个可迭代的和一个(可选的)键函数。它循环遍历iterable并使用keyfunction的值对它们进行分组:
>>> groupby("sentence", lambda c: c in 'nt')
<itertools.groupby object at 0x9805af4>
>>> [(k, list(g)) for k,g in groupby("sentence", lambda c: c in 'nt')]
[(False, ['s', 'e']), (True, ['n', 't']), (False, ['e']), (True, ['n']), (False, ['c', 'e'])]
其中具有关键函数的连续值的术语被组合在一起。 (这是一个常见的错误来源,实际上 - 人们忘记了如果他们想要对可能不是顺序的术语进行分组,他们必须首先按keyfunc排序。)
正如@JonClements猜测的那样,我想到的是
>>> special = dict.fromkeys(string.punctuation + string.whitespace, True)
>>> s = "One two three tab\ttabandspace\t end"
>>> [''.join(g) for k,g in groupby(s, special.get)]
['One', ' ', 'two', ' ', 'three', ' ', 'tab', '\t', 'tabandspace', '\t ', 'end']
对于我们组合分隔符的情况。如果值不在dict中,则.get
会返回None
。
答案 1 :(得分:7)
import re
import string
p = re.compile("[^{0}]+|[{0}]+".format(re.escape(
string.punctuation + string.whitespace)))
print p.findall("Now is the winter of our discontent")
我不喜欢使用正则表达式解决所有问题,但如果你想快速和短暂,我认为你没有太多选择。
我会解释正则表达式,因为你不熟悉它:
[...]
表示方括号内的任何字符[^...]
表示方括号+
背后意味着上一个或多个 x|y
表示匹配x
或y
因此,正则表达式匹配1个或多个字符,其中 all 必须是标点符号和空格,或者 none 必须是。 findall
方法查找模式的所有非重叠匹配。
答案 2 :(得分:4)
试试这个:
import re
re.split('(['+re.escape(string.punctuation + string.whitespace)+']+)',"Now is the winter of our discontent")
来自the Python documentation的解释:
如果在模式中使用捕获括号,则模式中所有组的文本也将作为结果列表的一部分返回。
答案 3 :(得分:3)
线性(O(n)
)时间的解决方案:
假设你有一个字符串:
original = "a, b...c d"
首先将所有分隔符转换为空格:
splitters = string.punctuation + string.whitespace
trans = string.maketrans(splitters, ' ' * len(splitters))
s = original.translate(trans)
现在s == 'a b c d'
。现在,您可以使用itertools.groupby
在空格和非空格之间切换:
result = []
position = 0
for _, letters in itertools.groupby(s, lambda c: c == ' '):
letter_count = len(list(letters))
result.append(original[position:position + letter_count])
position += letter_count
现在result == ['a', ', ', 'b', '...', 'c', ' ', 'd']
,这就是你需要的。
答案 4 :(得分:1)
根据您正在处理的文字,您可以将分隔符的概念简化为“字母和数字以外的任何内容”。如果这样可行,您可以使用以下正则表达式解决方案:
re.findall(r'[a-zA-Z\d]+|[^a-zA-Z\d]', text)
这假设您要分割每个单独的分隔符字符,即使它们是连续出现的,因此'foo..bar'
将变为['foo', '.', '.', 'bar']
。如果您希望['foo', '..', 'bar']
,请使用[a-zA-Z\d]+|[^a-zA-Z\d]+
(唯一不同的是在最后添加+
)。
答案 5 :(得分:1)
我的看法:
from string import whitespace, punctuation
import re
pattern = re.escape(whitespace + punctuation)
print re.split('([' + pattern + '])', 'now is the winter of')
答案 6 :(得分:0)
from string import punctuation, whitespace
s = "..test. and stuff"
f = lambda s, c: s + ' ' + c + ' ' if c in punctuation else s + c
l = sum([reduce(f, word).split() for word in s.split()], [])
print l
答案 7 :(得分:0)
对于任意分隔符集合:
def separate(myStr, seps):
answer = []
temp = []
for char in myStr:
if char in seps:
answer.append(''.join(temp))
answer.append(char)
temp = []
else:
temp.append(char)
answer.append(''.join(temp))
return answer
In [4]: print separate("Now is the winter of our discontent", set(' '))
['Now', ' ', 'is', ' ', 'the', ' ', 'winter', ' ', 'of', ' ', 'our', ' ', 'discontent']
In [5]: print separate("Now, really - it is the winter of our discontent", set(' ,-'))
['Now', ',', '', ' ', 'really', ' ', '', '-', '', ' ', 'it', ' ', 'is', ' ', 'the', ' ', 'winter', ' ', 'of', ' ', 'our', ' ', 'discontent']
希望这有帮助
答案 8 :(得分:-1)
from itertools import chain, cycle, izip
s = "Now is the winter of our discontent"
words = s.split()
wordsWithWhitespace = list( chain.from_iterable( izip( words, cycle([" "]) ) ) )
# result : ['Now', ' ', 'is', ' ', 'the', ' ', 'winter', ' ', 'of', ' ', 'our', ' ', 'discontent', ' ']