【问题标题】:String to tuple of words字符串到单词的元组
【发布时间】:2013-09-23 14:14:30
【问题描述】:

我将单词定义为一系列字符(从 a 到 Z),其中可能还包含撇号。我希望将一个句子拆分成单词,去掉单词中的撇号。

我目前正在执行以下操作以从一段文本中获取单词。

import re
text = "Don't ' thread \r\n on \nme ''\n "
words_iter = re.finditer(r'(\w|\')+', text)
words = (word.group(0).lower() for word in words_iter)
for i in words:
    print(i)

这给了我:

don't
'
thread
on
me
''

但我不想要的是:

dont
thread
on
me

如何更改我的代码以实现此目的?

请注意,我的输出中没有'

我也希望words 成为生成器。

【问题讨论】:

  • 你不是快到了,只需在你的for 循环中添加一个i = i.replace("'", ""),然后如果它不为空则生成字符串?
  • 您要解析多少输入?
  • @Tritium21 我正在构建一个语料库,所以我正在处理不同长度的文本文件。

标签: python regex python-3.x


【解决方案1】:

这看起来像是正则表达式的工作。

import re

text = "Don't ' thread \r\n on \nme ''\n "

# Define a function so as to make a generator
def get_words(text):

    # Find each block, separated by spaces
    for section in re.finditer("[^\s]+", text):

        # Get the text from the selection, lowercase it
        # (`.lower()` for Python 2 or if you hate people who use Unicode)
        section = section.group().casefold()

        # Filter so only letters are kept and yield
        section = "".join(char for char in section if char.isalpha())
        if section:
            yield section

list(get_words(text))
#>>> ['dont', 'thread', 'on', 'me']

正则表达式的解释:

[^    # An "inverse set" of characters, matches anything that isn't in the set
\s    # Any whitespace character
]+    # One or more times

所以这匹配任何非空白字符块。

【讨论】:

  • 请注意,这比我的版本慢了大约 4 倍。
  • 在您将.casefold/.lower 添加到您的帐户后,我将接受该时间安排。 ;) 我的在技术上更正确,因为我检查是否isalpha 而不是删除 ASCII 标点符号,但我会让那个幻灯片。
  • 我认为你可以降低一次,在re.finditer调用中使用.lower()
  • 不过,这将同时作用于整个字符串,这是我们想要避免的。
  • 用新的时间更新了我的解决方案。
【解决方案2】:
words = (x.replace("'", '') for x in text.split())
result = tuple(x for x in words if x)

...只对拆分数据进行一次迭代。

如果数据集很大,使用re.finditer而不是str.split(),避免将整个数据集读入内存:

words = (x.replace("'", '') for x in re.finditer(r'[^\s]+', text))
result = tuple(x for x in words if x)

...虽然,tuple()-ing 数据无论如何都会读取内存中的所有内容。

【讨论】:

  • 不会去掉“不要”中的 '
【解决方案3】:
import string
tuple(str(filter(lambda x: x if x in string.letters + string.whitespace else '', "strings don't have '")).split())

【讨论】:

  • 与 hcwhsa 一样,text.split() 一次处理整个 shebang,Baz 想要累积处理。
【解决方案4】:

使用str.translatere.finditer

>>> text = "Don't ' thread \r\n on \nme ''\n "
>>> import re
>>> from string import punctuation
>>> tab = dict.fromkeys(map(ord, punctuation))
def solve(text):
    for m in re.finditer(r'\b(\S+)\b', text):
        x = m.group(1).translate(tab).lower()
        if x : yield x
>>> list(solve(text))
['dont', 'thread', 'on', 'me']

时序对比:

>>> strs = text * 1000
>>> %timeit list(solve(strs))
10 loops, best of 3: 11.1 ms per loop
>>> %timeit list(get_words(strs))
10 loops, best of 3: 36.7 ms per loop
>>> strs = text * 10000
>>> %timeit list(solve(strs))
1 loops, best of 3: 146 ms per loop
>>> %timeit list(get_words(strs))
1 loops, best of 3: 411 ms per loop

【讨论】:

  • text.split() 一次处理整个shebang,Baz想累积处理。
  • 不错,但是破折号呢? "word1---word2 word3"
  • @hcwhsa text.lower() 将创建我希望避免的文本副本,因为它可能非常大
  • @hcwhsa 正如我在问题中所说,我只定义了一个词,包括从 a 到 Z 加上撇号。您的代码将通过非英文字母和数字等的字母。
  • @Baz 你可以使用正则表达式:x = re.sub(r'[^a-z]+', '', m.group(1), flags=re.I).lower()
猜你喜欢
  • 2014-12-16
  • 1970-01-01
  • 1970-01-01
  • 2013-01-21
  • 2021-07-15
  • 2021-12-03
  • 2014-03-29
  • 1970-01-01
  • 2023-03-05
相关资源
最近更新 更多