如何将一个句子字符串分割成单词,同时让标点符号成为单独的元素。

5

我目前正在尝试使用Python对语言数据进行标记化(tokenize),想知道是否有有效或内置的方法可以将句子字符串分割成单独的单词和分离的标点符号。例如:

'Hello, my name is John. What's your name?'

如果我在这个句子上使用split(),那么我会得到

['Hello,', 'my', 'name', 'is', 'John.', "What's", 'your', 'name?']

What I want to get is:

['Hello', ',', 'my', 'name', 'is', 'John', '.', "What's", 'your', 'name', '?']

我曾尝试使用查找字符串、找到标点符号、存储它们的索引、从字符串中删除它们,然后拆分字符串,并相应地插入标点符号等方法,但这种方法在处理大型语料库时似乎过于低效。

你知道是否有更有效的方法吗?

谢谢。

5个回答

5
你可以使用一个技巧:
text = "Hello, my name is John. What's your name?"
text = text.replace(",", " , ") # Add an space before and after the comma
text = text.replace(".", " . ") # Add an space before and after the point
text = text.replace("  ", " ") # Remove possible double spaces
mListtext.split(" ") # Generates your list

或者只用输入这个:

mList = input().replace(",", " , ").replace(".", " . ")replace("  ", " ").split(" ")

刚才忘了替换所有的“?”!希望你能理解我的逻辑并做出修改。 - Alexandre Aragão

1

单词分词并不像听起来那么简单。使用正则表达式或字符串替换的先前答案并不总是能处理缩写词或缩略语(例如,a.m.p.m.N.Y.D.I.YA.D.B.C.e.g.etc.i.e.Mr.Ms.Dr.),除非您编写更复杂的模式以处理此类情况(但仍将存在令人讨厌的异常情况)。您还需要决定如何处理其他标点符号,如"'$%、电子邮件地址和URL、数字序列(例如5,000.9933.3%)、连字符词(例如pre-processingavant-garde)、包含标点符号的名称(例如O'Neill)、缩略语(例如aren'tcan'tlet's)、英语所有格标记('s)等等。
我建议使用自然语言处理库来完成此任务,因为它们应该已经设置好了以处理大多数这些问题(尽管它们仍然会出现“错误”,您可以尝试修复)。请参见: 前三个是具有许多功能的完整工具包,除了分词之外,还有其他功能。最后一个是一个词性标注器,用于对文本进行分词。这只是其中的几个选择,还有其他选择,因此请尝试一些并查看哪种最适合您。它们将以不同的方式对您的文本进行分词,但在大多数情况下(不确定TreeTagger),您可以修改它们的分词决策以纠正错误。

1

以下是一种使用re.finditer的方法,它似乎至少能够处理您提供的示例数据:

inp = "Hello, my name is John. What's your name?"
parts = []
for match in re.finditer(r'[^.,?!\s]+|[.,?!]', inp):
    parts.append(match.group())

print(parts)

输出:

['Hello', ',', 'my', 'name', 'is', 'John', '.', "What's", 'your', 'name', '?']

这里的想法是匹配以下两种模式之一:
[^.,?!\s]+    which matches any non punctuation, non whitespace character
[.,?!]        which matches a single punctuation character

假定除了空格和标点符号之外的任何内容都应该是句子中的匹配词语/术语。

请注意,解决此问题的真正好方法是尝试在标点符号或空格上进行正则表达式分割。但是,re.split不支持在零宽度回顾上进行分割,因此我们被迫尝试使用re.finditer


0
您可以使用re.sub函数来替换所有在string.punctuation中定义的字符,这些字符后面紧跟一个空格,在其前面加上一个空格,最后可以使用str.split函数分割单词。
>>> s = "Hello, my name is John. What's your name?"
>>> 
>>> import string, re
>>> re.sub(fr'([{string.punctuation}])\B', r' \1', s).split()
['Hello', ',', 'my', 'name', 'is', 'John', '.', "What's", 'your', 'name', '?']

在Python2中

>>> re.sub(r'([%s])\B' % string.punctuation, r' \1', s).split()
['Hello', ',', 'my', 'name', 'is', 'John', '.', "What's", 'your', 'name', '?']

0

nltk 中的 TweetTokenizer 也可以用于此。

from nltk.tokenize import TweetTokenizer

tokenizer = TweetTokenizer()
tokenizer.tokenize('''Hello, my name is John. What's your name?''')

#op
['Hello', ',', 'my', 'name', 'is', 'John', '.', "What's", 'your', 'name', '?']

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接