我正在尝试使用下面的模式对字符串进行标记。
>>> splitter = re.compile(r'((\w*)(\d*)\-\s?(\w*)(\d*)|(?x)\$?\d+(\.\d+)?(\,\d+)?|([A-Z]\.)+|(Mr)\.|(Sen)\.|(Miss)\.|.$|\w+|[^\w\s])')
>>> splitter.split("Hello! Hi, I am debating this predicament called life. Can you help me?")
我得到以下输出。有人可以指出我需要纠正的事吗?我对一堆“无”感到困惑。此外,如果有更好的方法来标记字符串,我真的很感激额外的帮助。
['', 'Hello', None, None, None, None, None, None, None, None, None, None, '', '!', None, None, None, None, None, None, None, None, None, None, ' ', 'Hi', None,None, None, None, None, None, None, None, None, None, '', ',', None, None, None, None, None, None, None, None, None, None, ' ', 'I', None, None, None, None, None, None, None, None, None, None, ' ', 'am', None, None, None, None, None, None,None, None, None, None, ' ', 'debating', None, None, None, None, None, None, None, None, None, None, ' ', 'this', None, None, None, None, None, None, None, None, None, None, ' ', 'predicament', None, None, None, None, None, None, None, None, None, None, ' ', 'called', None, None, None, None, None, None, None, None, None, None, ' ', 'life', None, None, None, None, None, None, None, None, None, None, '', '.', None, None, None, None, None, None, None, None, None, None, ' ', 'Can', None, None, None, None, None, None, None, None, None, None, ' ', 'you', None, None, None, None, None, None, None, None, None, None, ' ', 'help', None, None,None, None, None, None, None, None, None, None, ' ', 'me', None, None, None, None, None, None, None, None, None, None, '', '?', None, None, None, None, None, None, None, None, None, None, '']
我想要的输出是: -
['Hello', '!', 'Hi', ',', 'I', 'am', 'debating', 'this', 'predicament', 'called', 'life', '.', 'Can', 'you', 'help', 'me', '?']
谢谢。
答案 0 :(得分:4)
re.split
会快速耗尽。优先选择findall
match
(或循环中的this|that|another|more
)
>>> s = "Hello! Hi, I am debating this predicament called life. Can you help me?"
>>> import re
>>> re.findall(r"\w+|\S", s)
['Hello', '!', 'Hi', ',', 'I', 'am', 'debating', 'this', 'predicament', 'called', 'life', '.', 'Can', 'you', 'help', 'me', '?']
>>>
这将标记定义为一个或多个“单词”字符,或单个字符不是空格。您可能更喜欢[A-Za-z]
或[A-Za-z0-9]
或其他内容而非\w
(允许下划线)。你甚至可能想要r"[A-Za-z]+|[0-9]+|\S"
如果Sen.
,Mr.
和Miss
(Mrs
和Ms
发生的事情?)对您很重要,那么您的正则表达式不应该列出它们应该只定义一个以.
结尾的标记,你应该有一个字典或一组可能的缩写。
将文本拆分成句子很复杂。您可能希望查看nltk
包而不是尝试重新发明轮子。
更新:如果您需要/想要区分令牌的类型,您可以获得索引或这样的名称,而不需要if / elif / elif /(可能很长)链。 ../否则:
>>> s = "Hello! Hi, I we 0 1 987?"
>>> pattern = r"([A-Za-z]+)|([0-9]+)|(\S)"
>>> list((m.lastindex, m.group()) for m in re.finditer(pattern, s))
[(1, 'Hello'), (3, '!'), (1, 'Hi'), (3, ','), (1, 'I'), (1, 'we'), (2, '0'), (2, '1'), (2, '987'), (3, '?')]
>>> pattern = r"(?P<word>[A-Za-z]+)|(?P<number>[0-9]+)|(?P<other>\S)"
>>> list((m.lastgroup, m.group()) for m in re.finditer(pattern, s))
[('word', 'Hello'), ('other', '!'), ('word', 'Hi'), ('other', ','), ('word', 'I'), ('word', 'we'), ('number', '0'), ('number', '1'), ('number', '987'), ('other'
, '?')]
>>>
答案 1 :(得分:4)
我推荐NLTK的标记符。那么你自己就不用担心繁琐的正则表达式了:
>>> import nltk
>>> nltk.word_tokenize("Hello! Hi, I am debating this predicament called life. Can you help me?")
['Hello', '!', 'Hi', ',', 'I', 'am', 'debating', 'this', 'predicament', 'called', 'life.', 'Can', 'you', 'help', 'me', '?']
答案 2 :(得分:2)
可能会遗漏一些东西,但我相信以下内容会起作用:
s = "Hello! Hi, I am debating this predicament called life. Can you help me?"
s.split(" ")
这假设你想要空格。你应该得到以下内容:
['Hello!', 'Hi,', 'I', 'am', 'debating', 'this', 'predicament', 'called', 'life.', 'Can', 'you', 'help', 'me?']
有了这个,如果你需要一个特定的作品,你可以循环通过它来获得你需要的东西。
希望这会有所帮助......
答案 3 :(得分:1)
你获得所有这些None
的原因是你的正则表达式中有许多括号内的组由|
分隔。每次正则表达式找到匹配项时,它只匹配|
给出的其中一个备选项。其他未使用的替代品中的括号组设置为None
。根据定义,re.split
会在每次获得匹配时报告所有括号组的值,因此结果中会有很多None
个。
您可以非常轻松地过滤掉这些内容(例如tokens = [t for t in tokens if t]
或类似内容),但我认为split
并不是您想要进行标记化的工具。 split
仅用于丢弃空白。如果你真的想要使用正则表达式来标记某些东西,这里是另一个方法的玩具示例(我甚至不打算解压缩你正在使用的那个怪物......使用re.VERBOSE
选项Ned的爱...但希望这个玩具示例会给你一个想法):
tokenpattern = re.compile(r"""
(?P<words>\w+) # Things with just letters and underscores
|(?P<numbers>\d+) # Things with just digits
|(?P<other>.+?) # Anything else
""", re.VERBOSE)
(?P<something>...
商家允许您通过以下代码中的名称识别您要查找的令牌类型:
for match in tokenpattern.finditer("99 bottles of beer"):
if match.group('words'):
# This token is a word
word = match.group('words')
#...
elif match.group('numbers'):
number = int(match.group('numbers')):
else:
other = match.group('other'):
请注意,这仍然是一个r.e.使用由|
分隔的一组带括号的组,因此在您的代码中会发生同样的事情:对于每个匹配,将定义一个组,其他组将设置为None
。此方法明确检查。
答案 4 :(得分:0)
也许他并不是这样说的,但John Machin的评论“str.split不是一个开始的地方”(作为Frank V's answer之后的交换的一部分)作为一个挑战。所以...
the_string = "Hello! Hi, I am debating this predicament called life. Can you help me?"
tokens = the_string.split()
punctuation = ['!', ',', '.', '?']
output_list = []
for token in tokens:
if token[-1] in punctuation:
output_list.append(token[:-1])
output_list.append(token[-1])
else:
output_list.append(token)
print output_list
这似乎提供了请求的输出。
当然,John的答案在代码行数方面更简单。但是,我有几点要支持这种解决方案。
我并不完全赞同Jamie Zawinski的'有些人在面对问题时,想“我知道,我会使用正则表达式。”现在他们有两个问题。 (他也没有读过我的内容。)我引用这一点的观点是,如果你不熟悉正则表达式,那么开始工作会很痛苦。
此外,虽然通常不会出现问题,但使用timeit进行测量时,上述解决方案的性能始终优于正则表达式解决方案。上述解决方案(删除了打印声明)大约8.9秒进入; John的正则表达式解决方案在大约11.8秒后出现。这涉及在运行2.4 GHz的四核双处理器系统上进行100次迭代的10次尝试。