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

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

应该是

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

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


当前回答

另一种不使用正则表达式的快速方法是首先替换字符,如下所示:

>>> 'a;bcd,ef g'.replace(';',' ').replace(',',' ').split()
['a', 'bcd', 'ef', 'g']

其他回答

使用替换两次:

a = '11223FROM33344INTO33222FROM3344'
a.replace('FROM', ',,,').replace('INTO', ',,,').split(',,,')

结果是:

['11223', '33344', '33222', '3344']

我必须想出自己的解决方案,因为我迄今为止测试的所有东西都在某一点上失败了。

>>> import re
>>> def split_words(text):
...     rgx = re.compile(r"((?:(?<!'|\w)(?:\w-?'?)+(?<!-))|(?:(?<='|\w)(?:\w-?'?)+(?=')))")
...     return rgx.findall(text)

至少在下面的例子中,它似乎工作得很好。

>>> split_words("The hill-tops gleam in morning's spring.")
['The', 'hill-tops', 'gleam', 'in', "morning's", 'spring']
>>> split_words("I'd say it's James' 'time'.")
["I'd", 'say', "it's", "James'", 'time']
>>> split_words("tic-tac-toe's tic-tac-toe'll tic-tac'tic-tac we'll--if tic-tac")
["tic-tac-toe's", "tic-tac-toe'll", "tic-tac'tic-tac", "we'll", 'if', 'tic-tac']
>>> split_words("google.com email@google.com split_words")
['google', 'com', 'email', 'google', 'com', 'split_words']
>>> split_words("Kurt Friedrich Gödel (/ˈɡɜːrdəl/;[2] German: [ˈkʊɐ̯t ˈɡøːdl̩] (listen);")
['Kurt', 'Friedrich', 'Gödel', 'ˈɡɜːrdəl', '2', 'German', 'ˈkʊɐ', 't', 'ˈɡøːdl', 'listen']
>>> split_words("April 28, 1906 – January 14, 1978) was an Austro-Hungarian-born Austrian...")
['April', '28', '1906', 'January', '14', '1978', 'was', 'an', 'Austro-Hungarian-born', 'Austrian']

创建一个函数,将两个字符串(要拆分的源字符串和分隔符的拆分列表字符串)作为输入,并输出拆分单词列表:

def split_string(source, splitlist):
    output = []  # output list of cleaned words
    atsplit = True
    for char in source:
        if char in splitlist:
            atsplit = True
        else:
            if atsplit:
                output.append(char)  # append new word after split
                atsplit = False
            else: 
                output[-1] = output[-1] + char  # continue copying characters until next split
    return output

我喜欢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,因为每个组都是一个迭代器,所以表达式将变得懒惰)

我最近需要这样做,但需要一个与标准库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])

注意:此函数仅在分隔符由单个字符组成时有用(正如我的用例)。