我想我想做的是一项相当常见的任务,但我在网上找不到任何参考资料。我有带标点符号的文本,我想要一个单词列表。
"Hey, you - what are you doing here!?"
应该是
['hey', 'you', 'what', 'are', 'you', 'doing', 'here']
但Python的str.split()只对一个参数有效,所以在用空格拆分后,所有单词都带有标点符号。有什么想法吗?
我想我想做的是一项相当常见的任务,但我在网上找不到任何参考资料。我有带标点符号的文本,我想要一个单词列表。
"Hey, you - what are you doing here!?"
应该是
['hey', 'you', 'what', 'are', 'you', 'doing', 'here']
但Python的str.split()只对一个参数有效,所以在用空格拆分后,所有单词都带有标点符号。有什么想法吗?
当前回答
这么多的答案,但我找不到任何能有效解决问题标题所要求的问题的解决方案(而是在多个可能的分隔符上拆分,许多答案在任何非单词上拆分,这是不同的)。因此,这是标题中问题的答案,它依赖于Python的标准和高效的重新模块:
>>> import re # Will be splitting on: , <space> - ! ? :
>>> filter(None, re.split("[, \-!?:]+", "Hey, you - what are you doing here!?"))
['Hey', 'you', 'what', 'are', 'you', 'doing', 'here']
哪里:
[…]匹配其中列出的分隔符之一,正则表达式中的\-是为了防止将-作为字符范围指示符(如a-Z)进行特殊解释,+跳过一个或多个分隔符(由于filter(),它可以省略,但这将不必要地在匹配的单字符分隔符之间产生空字符串),以及filter(None,…)删除可能由前导和尾随分隔符创建的空字符串(因为空字符串具有假布尔值)。
正如问题标题中所要求的,这个re.split()精确地“使用多个分隔符进行拆分”。
此外,该解决方案不受其他一些解决方案中单词中非ASCII字符的问题的影响(参见ghostdog74答案的第一条注释)。
re模块比“手动”执行Python循环和测试更高效(速度和简洁)!
其他回答
专业提示:使用string.translate进行Python最快的字符串操作。
一些证据。。。
首先,缓慢的方式(抱歉pprzemek):
>>> import timeit
>>> S = 'Hey, you - what are you doing here!?'
>>> def my_split(s, seps):
... res = [s]
... for sep in seps:
... s, res = res, []
... for seq in s:
... res += seq.split(sep)
... return res
...
>>> timeit.Timer('my_split(S, punctuation)', 'from __main__ import S,my_split; from string import punctuation').timeit()
54.65477919578552
接下来,我们使用re.findall()(如建议的答案所示)。更快:
>>> timeit.Timer('findall(r"\w+", S)', 'from __main__ import S; from re import findall').timeit()
4.194725036621094
最后,我们使用translate:
>>> from string import translate,maketrans,punctuation
>>> T = maketrans(punctuation, ' '*len(punctuation))
>>> timeit.Timer('translate(S, T).split()', 'from __main__ import S,T,translate').timeit()
1.2835021018981934
说明:
string.translate是用C实现的,与Python中的许多字符串操作函数不同,string.ttranslate不会生成新字符串。所以它的速度和字符串替换一样快。
不过,这有点尴尬,因为它需要一个翻译表来实现这一魔术。您可以使用maketrans()方便函数创建转换表。这里的目标是将所有不需要的字符转换为空格。一换一的替代品。同样,不会产生新数据。所以这很快!
接下来,我们使用旧的split()。默认情况下,split()将对所有空白字符进行操作,将它们分组以进行拆分。结果将是您想要的单词列表。而且这种方法几乎比re.findall()快4倍!
我最近需要这样做,但需要一个与标准库str.split函数有点匹配的函数,当使用0或1参数调用时,该函数的行为与标准库相同。
def split_many(string, *separators):
if len(separators) == 0:
return string.split()
if len(separators) > 1:
table = {
ord(separator): ord(separator[0])
for separator in separators
}
string = string.translate(table)
return string.split(separators[0])
注意:此函数仅在分隔符由单个字符组成时有用(正如我的用例)。
re.split()
re.split(模式,字符串[,maxsplit=0])按模式的出现次数拆分字符串。如果模式中使用了捕获括号,那么模式中所有组的文本也会作为结果列表的一部分返回。如果maxsplit为非零,则最多发生maxsplit拆分,字符串的剩余部分将作为列表的最后一个元素返回。(不兼容注意:在最初的Python1.5版本中,maxsplit被忽略。这在以后的版本中得到了修复。)
>>> re.split('\W+', 'Words, words, words.')
['Words', 'words', 'words', '']
>>> re.split('(\W+)', 'Words, words, words.')
['Words', ', ', 'words', ', ', 'words', '.', '']
>>> re.split('\W+', 'Words, words, words.', 1)
['Words', 'words, words.']
遇到与@ooboo相同的问题并找到此主题@ghostdog74启发了我,也许有人觉得我的解决方案很有用
str1='adj:sg:nom:m1.m2.m3:pos'
splitat=':.'
''.join([ s if s not in splitat else ' ' for s in str1]).split()
在空格处输入内容,如果不想在空格处拆分,请使用相同的字符进行拆分。
这是我与多个决策者的分歧:
def msplit( str, delims ):
w = ''
for z in str:
if z not in delims:
w += z
else:
if len(w) > 0 :
yield w
w = ''
if len(w) > 0 :
yield w