为什么“是”和“to”被NLTK RegexpTokenizer()中的正则表达式删除?

时间:2018-02-02 05:18:02

标签: regex nltk tokenize

我想标记化

s = ("mary went to garden. where is mary? "
     "mary is carrying apple and milk. "
     "what mary is carrying? apple,milk")

进入

['mary', 'went', 'to', 'garden', '.', 
 'where', 'is', 'mary', '?', 
 'mary', 'is', 'carrying', 'apple', 'and', 'milk', '.', 
 'what', 'mary', 'is', 'carrying', '?', 'apple,milk']

请注意,我希望将'apple,milk'保留为一个单词。

我的代码是:

from nltk.tokenize import RegexpTokenizer
tokenizer = RegexpTokenizer('\w+[\]|\w+[\,]\w+|\.|\?')
s = "mary went to garden. where is mary? mary is carrying apple and milk. what mary is carrying? apple,milk"
tokenizer.tokenize(s)

结果是:

['mary', 'went', 'garden', '.', 
 'where', 'mary', '?', 
 'mary', 'carrying', 'apple', 'and', 'milk', '.', 
 'what', 'mary', 'carrying', '?', 'apple,milk']

但是,'is''to'丢失了。如何保留它们?

2 个答案:

答案 0 :(得分:1)

您的正则表达式模式根本无法捕获丢失的单词。

你可以看到这是一个正则表达式工具,或者使用带有附加参数的RegexpTokenizer('\w+[\]|\w+[\,]\w+|\.|\?', True)来显示间隙而不是令牌(doc)。

更新:
这是一个模式,可以找到您指定的所有标记:

\w+[\,]\w+|\w+|\.|\?

备注:使用正则表达式替代方法时,按长度(通常从最长到最短)对它们进行排序非常重要。 [\]对我来说没有意义,语法上也不正确。

Online demo

答案 1 :(得分:1)

RegexpTokenizer只根据https://github.com/nltk/nltk/blob/develop/nltk/tokenize/regexp.py#L78

输入的正则表达式执行re.findall函数
 def tokenize(self, text):
        self._check_regexp()
        # If our regexp matches gaps, use re.split:
        if self._gaps:
            if self._discard_empty:
                return [tok for tok in self._regexp.split(text) if tok]
            else:
                return self._regexp.split(text)

        # If our regexp matches tokens, use re.findall:
        else:
            return self._regexp.findall(text)

基本上,你正在做:

>>> import re
>>> rg = re.compile(r'\w+[\]|\w+[\,]\w+|\.|\?')
>>> sent = "mary went to garden. where is mary? mary is carrying apple and milk. what mary is carrying? apple,milk" 
>>> rg.findall(sent)
['mary', 'went', 'garden', '.', 'where', 'mary', '?', 'mary', 'carrying', 'apple', 'and', 'milk', '.', 'what', 'mary', 'carrying', '?', 'apple,milk']

查看正则表达式的解释\w+[\]|\w+[\,]\w+|\.|\?https://regex101.com/r/ail12t/1/

正则表达式有3种选择:

  • \w+[\]|\w+[\,]\w+
    • 第一部分\w+匹配任何单词字符(等于[a-zA-Z0-9_])无限次
    • 第二部分[\]|\w+[\,],匹配\w+范围内的任何字词以及]|[,字符
    • 口渴部分\w+匹配任何单词字符(等于[a-zA-Z0-9_])无限次
  • \.:找到.符号并将其匹配

  • \? :: TF ?符号并与之匹配

两个字符单词的原因是" gobbled" up是因为w+w+w+正则表达式的第一个替代中的多个\w+[\]|\w+[\,]\w+。这意味着正则表达式只捕获/找到所有具有最小值> = 3个字符的单词。

实际上,我认为正则表达式可以进一步简化,您可以轻松地将其分解为小单位并将其拼凑起来。

使用\w+,它只会匹配所有字词并排除标点符号:

>>> rg = re.compile(r'\w+')
>>> sent = "mary went to garden. where is mary? mary is carrying apple and milk. what mary is carrying? apple,milk" 
>>> rg.findall(sent)
['mary', 'went', 'to', 'garden', 'where', 'is', 'mary', 'mary', 'is', 'carrying', 'apple', 'and', 'milk', 'what', 'mary', 'is', 'carrying', 'apple', 'milk']

然后要捕捉标点符号[[\]\,\-\|\.],只需将它们添加为由|分隔的替代项,即

>>> rg = re.compile(r'\w+|[[\]\,\-\|\.]')
>>> rg.findall(sent)
['mary', 'went', 'to', 'garden', '.', 'where', 'is', 'mary', 'mary', 'is', 'carrying', 'apple', 'and', 'milk', '.', 'what', 'mary', 'is', 'carrying', 'apple', ',', 'milk']