我想我想做的是一项相当常见的任务,但我在网上找不到任何参考资料。我有带标点符号的文本,我想要一个单词列表。

"Hey, you - what are you doing here!?"

应该是

['hey', 'you', 'what', 'are', 'you', 'doing', 'here']

但Python的str.split()只对一个参数有效,所以在用空格拆分后,所有单词都带有标点符号。有什么想法吗?


当前回答

我喜欢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]

sep__contains__是“in”运算符使用的方法。基本上与

lambda ch: ch in sep

但在这里更方便。

groupby获取字符串和函数。它使用该函数将字符串分成多个组:每当函数值发生变化时,就会生成一个新的组。因此,sep__contains__正是我们需要的。

groupby返回一个对序列,其中对[0]是我们函数的结果,对[1]是一个组。使用“if not k”,我们筛选出带有分隔符的组(因为sep.__contains__的结果在分隔符上为True)。好了,就这些了-现在我们有一个组序列,每个组都是一个单词(组实际上是一个可迭代的,所以我们使用join将其转换为字符串)。

这个解决方案非常通用,因为它使用一个函数来分隔字符串(您可以根据需要的任何条件进行拆分)。此外,它不创建中间字符串/列表(您可以删除join,因为每个组都是一个迭代器,所以表达式将变得懒惰)

其他回答

使用panda的series.str.split方法可以获得相同的结果,而不是使用re-module函数re.split。

首先,使用上述字符串创建一个系列,然后将该方法应用于该系列。

thestring=pd.Series(“嘿,你-你在这里干什么!?”)thestring.str.split(pat=',|-')

参数pat接受分隔符并将拆分字符串作为数组返回。这里,使用|(或运算符)传递两个分隔符。输出如下:

[嘿,你,你在这里干什么!?]

实现这一点的另一种方法是使用自然语言工具包(nltk)。

import nltk
data= "Hey, you - what are you doing here!?"
word_tokens = nltk.tokenize.regexp_tokenize(data, r'\w+')
print word_tokens

这张照片显示:[“嘿”、“你”、“什么”、“是”、“您”、“正在做”、“在这里”]

这种方法的最大缺点是需要安装nltk包。

好处是,一旦获得令牌,就可以使用nltk包的其余部分做很多有趣的事情。

首先,我想同意其他人的观点,即基于正则表达式或str.translate(…)的解决方案是最具性能的。对于我的用例,这个函数的性能并不重要,所以我想添加一些我认为符合这个标准的想法。

我的主要目标是将其他一些答案中的想法归纳为一个解决方案,该解决方案可以适用于包含不仅仅是正则表达式单词的字符串(即,将标点符号字符的显式子集列入黑名单,而不是将单词字符列入白名单)。

注意,在任何方法中,也可以考虑使用string.p标点符号代替手动定义的列表。

选项1-re.sub

我很惊讶地发现到目前为止还没有使用re.sub(…)的答案。我发现这是解决这个问题的一种简单而自然的方法。

import re

my_str = "Hey, you - what are you doing here!?"

words = re.split(r'\s+', re.sub(r'[,\-!?]', ' ', my_str).strip())

在这个解决方案中,我将对re.sub(…)的调用嵌套在re.split(…)内部-但如果性能很关键,那么在外部编译正则表达式可能会很有用-对于我的用例来说,差异并不大,所以我更喜欢简单性和可读性。

选项2-str.replace

这是几行,但它的优点是可以扩展,而不必检查是否需要转义正则表达式中的某个字符。

my_str = "Hey, you - what are you doing here!?"

replacements = (',', '-', '!', '?')
for r in replacements:
    my_str = my_str.replace(r, ' ')

words = my_str.split()

如果能够将str.replace映射到字符串,那会很好,但我不认为这可以用不可变的字符串来实现,虽然映射到一个字符列表是可行的,但对每个字符运行每个替换听起来都很过分。(编辑:有关功能示例,请参见下一个选项。)

选项3-functools.reduce

(在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()

试试看:

import re

phrase = "Hey, you - what are you doing here!?"
matches = re.findall('\w+', phrase)
print matches

这将打印['Hey','you','what','are','you','doing','here']

另一种方式,不使用正则表达式

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()