需要帮助在python中拆分字符串

时间:2010-08-03 01:14:06

标签: python regex string-split

我正在尝试使用下面的模式对字符串进行标记。

>>> 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', '?']

谢谢。

5 个答案:

答案 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.MissMrsMs发生的事情?)对您很重要,那么您的正则表达式不应该列出它们应该只定义一个以.结尾的标记,你应该有一个字典或一组可能的缩写。

将文本拆分成句子很复杂。您可能希望查看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次尝试。