oob*_*boo 631 python string split
我认为我想做的是一项相当普遍的任务,但我在网上找不到任何参考.我有带标点符号的文字,我想要一个单词列表.
"Hey, you - what are you doing here!?"
Run Code Online (Sandbox Code Playgroud)
应该
['hey', 'you', 'what', 'are', 'you', 'doing', 'here']
Run Code Online (Sandbox Code Playgroud)
但是Python str.split()
只能使用一个参数,所以在用空格分割之后,我所有的单词都带有标点符号.有任何想法吗?
gim*_*mel 536
re.split(pattern,string [,maxsplit = 0])
按模式的出现拆分字符串.如果在模式中使用捕获括号,则模式中所有组的文本也将作为结果列表的一部分返回.如果maxsplit非零,则最多发生maxsplit拆分,并且字符串的其余部分将作为列表的最后一个元素返回.(不兼容性说明:在最初的Python 1.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.']
Run Code Online (Sandbox Code Playgroud)
Ric*_*dle 442
正则表达式合理的情况:
import re
DATA = "Hey, you - what are you doing here!?"
print re.findall(r"[\w']+", DATA)
# Prints ['Hey', 'you', 'what', 'are', 'you', 'doing', 'here']
Run Code Online (Sandbox Code Playgroud)
Lou*_* LC 352
另一种没有正则表达式的快速方法是首先替换字符,如下所示:
>>> 'a;bcd,ef g'.replace(';',' ').replace(',',' ').split()
['a', 'bcd', 'ef', 'g']
Run Code Online (Sandbox Code Playgroud)
Eri*_*got 287
如此多的答案,但我找不到任何解决方案,有效地解决了问题的标题字面要求(分裂多个可能的分隔符 - 相反,许多答案删除任何不是一个单词的东西,这是不同的).所以这里是标题中问题的答案,它依赖于Python的标准和高效re
模块:
>>> 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']
Run Code Online (Sandbox Code Playgroud)
哪里:
[…]
比赛一个内所列的分离器,\-
在正则表达式是在这里以防止特殊解释-
为字符范围指示器(如在A-Z
),+
跳过一个或多个定界符(它可以省略感谢filter()
,但是这将不必要地产生匹配隔板之间空字符串),并filter(None, …)
删除可能由前导和尾随分隔符创建的空字符串(因为空字符串具有false布尔值).re.split()
正如问题标题中所要求的那样,这恰好"与多个分隔符分开".
此解决方案还可以免受其他一些解决方案中的非ASCII字符问题的影响(请参阅ghostdog74的答案的第一条评论).
该re
模块比使用Python循环和"手动"测试更有效(速度和简洁)!
gho*_*g74 55
另一种方式,没有正则表达式
import string
punc = string.punctuation
thestring = "Hey, you - what are you doing here!?"
s = list(thestring)
''.join([o for o in s if not o in punc]).split()
Run Code Online (Sandbox Code Playgroud)
Dav*_*ave 39
专业提示: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
Run Code Online (Sandbox Code Playgroud)
接下来,我们使用re.findall()
(由建议的答案给出).快多了:
>>> timeit.Timer('findall(r"\w+", S)', 'from __main__ import S; from re import findall').timeit()
4.194725036621094
Run Code Online (Sandbox Code Playgroud)
最后,我们使用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
Run Code Online (Sandbox Code Playgroud)
说明:
string.translate
在C中实现,与Python中的许多字符串操作函数不同,string.translate
不会产生新的字符串.所以它的速度和字符串替换一样快.
但是,它有点尴尬,因为它需要一个翻译表才能做到这一点.您可以使用maketrans()
便利功能制作翻译表.这里的目标是将所有不需要的字符转换为空格.一对一的替代品.同样,没有产生新数据.所以这很快!
接下来,我们使用旧的split()
.split()
默认情况下,它将对所有空白字符进行操作,将它们组合在一起以进行拆分.结果将是您想要的单词列表.这种方法几乎快了4倍re.findall()
!
ppr*_*mek 24
有点迟到的答案:),但我有一个类似的困境,并不想使用'重'模块.
def my_split(s, seps):
res = [s]
for sep in seps:
s, res = res, []
for seq in s:
res += seq.split(sep)
return res
print my_split('1111 2222 3333;4444,5555;6666', [' ', ';', ','])
['1111', '', '2222', '3333', '4444', '5555', '6666']
Run Code Online (Sandbox Code Playgroud)
Tay*_*ton 12
首先,我想与其他人一致认为正则表达式或str.translate(...)
基于解决方案的性能最高.对于我的用例,这个函数的性能并不重要,所以我想添加一些我用这个标准考虑的想法.
我的主要目标是将一些其他答案中的想法概括为一个解决方案,该解决方案可以用于包含不仅仅是正则表达式单词的字符串(即,将标点符号的明确子集列入黑名单与白名单字符列入黑名单).
请注意,在任何方法中,也可以考虑使用string.punctuation
代替手动定义的列表.
我很惊讶地看到目前为止没有回答使用re.sub(...).我觉得这个问题简单而自然.
import re
my_str = "Hey, you - what are you doing here!?"
words = re.split(r'\s+', re.sub(r'[,\-!?]', ' ', my_str).strip())
Run Code Online (Sandbox Code Playgroud)
在这个解决方案中,我嵌入了对re.sub(...)
内部的调用re.split(...)
- 但是如果性能很关键,那么在外部编译正则表达式可能是有益的 - 对于我的用例,差异并不显着,所以我更喜欢简单性和可读性.
这是一些更多的行,但它具有可扩展的好处,而无需检查是否需要在正则表达式中转义某个字符.
my_str = "Hey, you - what are you doing here!?"
replacements = (',', '-', '!', '?')
for r in replacements:
my_str = my_str.replace(r, ' ')
words = my_str.split()
Run Code Online (Sandbox Code Playgroud)
能够将str.replace映射到字符串本来是很好的,但是我不认为它可以用不可变的字符串来完成,并且对着字符列表的映射可以工作,对每个字符运行每个替换听起来太过分 (编辑:有关功能示例,请参阅下一个选项.)
(在Python 2中,reduce
可以在全局命名空间中使用,而无需从functools导入它.)
import functools
my_str = "Hey, you - what are you doing here!?"
replacements = (',', '-', '!', '?')
my_str = functools.reduce(lambda s, sep: s.replace(sep, ' '), replacements, my_str)
words = my_str.split()
Run Code Online (Sandbox Code Playgroud)
nin*_*cko 10
join = lambda x: sum(x,[]) # a.k.a. flatten1([[1],[2,3],[4]]) -> [1,2,3,4]
# ...alternatively...
join = lambda lists: [x for l in lists for x in l]
Run Code Online (Sandbox Code Playgroud)
然后这变成了三个班轮:
fragments = [text]
for token in tokens:
fragments = join(f.split(token) for f in fragments)
Run Code Online (Sandbox Code Playgroud)
说明
这就是Haskell被称为List monad的内容.monad背后的想法是,一旦"在monad"中你"留在monad",直到有什么东西把你带出去.例如在Haskell中,假设您将python range(n) -> [1,2,...,n]
函数映射到List.如果结果是List,它将就地附加到List,所以你会得到类似的东西map(range, [3,4,1]) -> [0,1,2,0,1,2,3,0]
.这被称为map-append(或mappend,或类似的东西).这里的想法是你已经应用了这个操作(拆分令牌),每当你这样做时,你就把结果加入到列表中.
您可以将其抽象为函数并tokens=string.punctuation
默认具有.
这种方法的优点:
我喜欢re,但这是我没有它的解决方案:
from itertools import groupby
sep = ' ,-!?'
s = "Hey, you - what are you doing here!?"
print [''.join(g) for k, g in groupby(s, sep.__contains__) if not k]
Run Code Online (Sandbox Code Playgroud)
sep.__contains__是 'in' 运算符使用的一种方法。基本上是一样的
lambda ch: ch in sep
Run Code Online (Sandbox Code Playgroud)
但这里更方便。
groupby获取我们的字符串和函数。它使用该函数将字符串分成组:每当函数值发生变化时,就会生成一个新组。所以,sep.__contains__正是我们所需要的。
groupby返回一个对的序列,其中 pair[0] 是我们函数的结果,pair[1] 是一个组。使用'if not k'我们过滤掉带有分隔符的组(因为sep.__contains__的结果在分隔符上是 True)。好吧,就是这样 - 现在我们有一个组序列,其中每个组都是一个单词(组实际上是一个可迭代的,所以我们使用join将其转换为字符串)。
这个解决方案非常通用,因为它使用一个函数来分隔字符串(您可以根据需要的任何条件进行拆分)。此外,它不会创建中间字符串/列表(您可以删除join并且表达式将变得懒惰,因为每个组都是一个迭代器)
小智 6
使用替换两次:
a = '11223FROM33344INTO33222FROM3344'
a.replace('FROM', ',,,').replace('INTO', ',,,').split(',,,')
Run Code Online (Sandbox Code Playgroud)
结果是:
['11223', '33344', '33222', '3344']
Run Code Online (Sandbox Code Playgroud)
尝试这个:
import re
phrase = "Hey, you - what are you doing here!?"
matches = re.findall('\w+', phrase)
print matches
Run Code Online (Sandbox Code Playgroud)
这将打印 ['Hey', 'you', 'what', 'are', 'you', 'doing', 'here']