【问题标题】:Extracting whole words提取整个单词
【发布时间】:2011-04-19 14:22:12
【问题描述】:

我有大量真实世界的文本,我需要从中提取单词以输入到拼写检查器中。我想在没有太多噪音的情况下提取尽可能多的有意义的词。我知道这里有很多正则表达式忍者,所以希望有人可以帮助我。

目前我正在使用'[a-z]+' 提取所有字母序列。这是一个不错的近似值,但它会拖出很多垃圾。

理想情况下我想要一些正则表达式(不一定要漂亮或高效),它可以提取由自然单词分隔符(例如 [/-_,.: ] 等)分隔的所有字母序列,并忽略任何具有非法边界的字母序列。

但是,我也很高兴能够获得所有不与数字相邻的字母序列。例如'pie21' 不会提取'pie',但'http://foo.com' 会提取['http', 'foo', 'com']

我尝试了 lookaheadlookbehind 断言,但它们是按字符应用的(例如,当我希望它不返回任何内容时,re.findall('(?<!\d)[a-z]+(?!\d)', 'pie21') 将返回 'pi')。我尝试将 alpha 部分包装为一个术语 ((?:[a-z]+)),但没有帮助。

更多细节:数据是一个电子邮件数据库,所以它大多是普通数字的简单英语,但偶尔会有像GIHQ4NWL0S5SCGBDD40ZXE5IDP13TYNEAAC7A21C0这样的垃圾字符串我想完全忽略.我假设任何带有数字的字母顺序都是垃圾。

【问题讨论】:

  • 更好地使用带有正则表达式的原始字符串。 \d 恰好可以工作,但其他转义序列会失败,这可能很难调试。

标签: python regex word alphabetical text-extraction


【解决方案1】:

如果您将自己限制为 ASCII 字母,则使用(带有re.I 选项集)

\b[a-z]+\b

\b 是单词边界锚点,仅匹配字母数字“单词”的开头和结尾。所以\b[a-z]+\b 匹配pie,但不匹配pie2121pie

要同时允许其他非 ASCII 字母,您可以使用如下内容:

\b[^\W\d_]+\b

它还允许重音字符等。您可能需要设置 re.UNICODE 选项,尤其是在使用 Python 2 时,以允许 \w 简写匹配非 ASCII 字母。

[^\W\d_] 作为否定字符类允许除数字和下划线以外的任何字母数字字符。

【讨论】:

  • 这听起来完全符合我的要求,但我无法让 bally \bs 工作。将text 设置为一些正常的句子,re.findall('\b[a-z]+\b', text, re.I) 什么也不返回。无论我在方括号中放什么(或使用searchmatch),它似乎也无济于事。使用\B 可以得到一些结果,但会去掉每个单词的第一个和最后一个字符。尽管听起来很懒惰,但我现在太累了,无法接受新概念;你有没有机会知道它为什么不起作用?或者您可以发布一个文字示例,说明在这种情况下您将如何使用它?
  • 这正是我对您的问题发表评论的原因。如果您不使用原始字符串 (r"\b[a-z]\b"),\b 将被解释为退格字符。
  • Ooooooooooooh,这就是你的意思:)。抱歉,现在是早上 5:30,我永远不会建立这种联系。只需添加 r 就可以了!谢谢你,先生。
  • 一般来说这是可行的,但它会在带有特殊字符的单词上失败(例如wenn bei Beförderungen Schäden
  • @yekta:如果您使用re.UNICODEre.LOCALE 选项编译正则表达式,则不会。我应该将其添加到我的答案中。
【解决方案2】:

你熟悉word boundaries? (\b)。您可以使用序列周围的\b 提取单词并匹配其中的字母:

\b([a-zA-Z]+)\b

例如,这会抓取整个单词,但会在连字符、句点、分号等标记处停止。

您可以在python manual 上使用\b 序列和其他序列

编辑此外,如果您要查找比赛前后的数字,您可以使用否定的前瞻/后视:

(?!\d)   # negative look-ahead for numbers
(?<!\d)  # negative look-behind for numbers

【讨论】:

  • 根据 Tim 的回答,\b 听起来像我想要的,但它的播放效果并不好。有任何想法吗?我之前尝试过前瞻和后瞻,但它们似乎匹配所有字符,直到与数字相邻的字符,因此不要完全忽略其中带有数字的单词。它还抱怨前瞻需要固定宽度的模式,其中包含 +s。
  • @Pie21:那就用个位数的匹配。我们不在乎它后面/前面有多少个数字,只要有一个数字。 example
  • 我得到了这个工作 [ re.findall(r"\b([a-zA-Z]+)\b",content, re.I) ] 但它似乎没有除草出正斜杠和反斜杠。以下是一些出现的单词:'[endif]'、'$'、'8'、'/small'、'/li'
【解决方案3】:

怎么样:

import re
yourString="pie 42 http://foo.com GIHQ4NWL0S5SCGBDD40ZXE5IDP13TYNEA  pie42"
filter (lambda x:re.match("^[a-zA-Z]+$",x),[x for x in set(re.split("[\s:/,.:]",yourString))])

注意:

  • split 将您的字符串分解为潜在的候选词 => 返回“潜在单词”列表
  • set 使唯一性过滤 => 转换 set 中的列表,从而删除多次出现的条目。此步骤不是强制性的。
  • filter 减少候选者的数量:获取一个列表,对每个元素应用一个测试函数,并返回一个通过测试的元素的列表。在我们的例子中,测试函数是“匿名的”
  • lambda : 匿名函数,获取一个项目并检查它是否是一个单词(仅限大写或小写字母)

编辑:添加了一些解释

【讨论】:

  • 虽然丑,但它确实有效!干杯!但是我可以再问一个问题:因为我不会说 lambda OR 过滤器,有没有办法用re.finditer() 做那种事情?我还需要跟踪文本中每个匹配项的开始和结束索引。
【解决方案4】:

示例代码

print re.search(ur'(?u)ривет\b', ur'Привет')
print re.search(ur'(?u)\bривет\b', ur'Привет')

s = ur"abcd ААБВ"
import re
rx1 = re.compile(ur"(?u)АБВ")
rx2 = re.compile(ur"(?u)АБВ\b")
rx3 = re.compile(ur"(?u)\bАБВ\b")
print rx1.findall(s)
print rx2.findall(s)
print rx3.findall(s)

【讨论】:

    猜你喜欢
    • 2013-07-11
    • 2021-03-15
    • 1970-01-01
    • 2018-04-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-20
    相关资源
    最近更新 更多