Python通过括号分割字符串

7
我之前提出了一个问题(Python splitting unknown string by spaces and parentheses),这个问题在我改变思路之前非常好用。但是我仍然没有掌握正则表达式,所以需要一些帮助。
如果用户输入以下内容: new test (test1 test2 test3) test "test5 test6" 我希望它的输出结果像这个变量一样: ["new", "test", "test1 test2 test3", "test", "test5 test6"] 换句话说,如果一个单词由空格分隔,则将其与下一个单词分开;如果在括号中,则将整个单词组拆分并删除它们。引号也是如此。
我目前正在使用这段代码,但它不符合上述标准(来自上面链接中的答案):
>>>import re
>>>strs = "Hello (Test1 test2) (Hello1 hello2) other_stuff"
>>>[", ".join(x.split()) for x in re.split(r'[()]',strs) if x.strip()]
>>>['Hello', 'Test1, test2', 'Hello1, hello2', 'other_stuff']

这很有效但有一个问题,如果你有这个:

strs = "Hello Test (Test1 test2) (Hello1 hello2) other_stuff"

它会将Hello和Test合并为一个分割而不是两个。

它也不允许同时使用括号和引号进行拆分。


2
看一下贪婪匹配和非贪婪匹配。 - XORcist
@möter 你有教程链接吗?我找到的大多数都是关于它的问题,对我没有什么帮助,而且我也看不太懂Python文档。如果那是唯一的选择,那就只好这样了。 - TrevorPeyton
抱歉,我误读了问题。但是这里有官方教程的链接:http://docs.python.org/2/library/re.html - XORcist
5个回答

6
答案很简单:
re.findall('\[[^\]]*\]|\([^\)]*\)|\"[^\"]*\"|\S+',strs)

3

这超出了正则表达式的能力范围。考虑使用pyparsing代替。它可以进行递归下降解析。对于此任务,您可以使用:

from pyparsing import *
import string, re

RawWord = Word(re.sub('[()" ]', '', string.printable))
Token = Forward()
Token << ( RawWord | 
           Group('"' + OneOrMore(RawWord) + '"') |
           Group('(' + OneOrMore(Token) + ')') )
Phrase = ZeroOrMore(Token)

Phrase.parseString(s, parseAll=True)

这个方法可以处理奇怪的空格和嵌套的括号。相对于使用大型正则表达式,它更易于阅读,因此更容易进行调整。

我知道您已经解决了自己的问题,但是这篇文章是谷歌搜索结果中排名最高的之一,而pyparsing库却不为人所知。


1
你的问题没有很好地定义。
你对规则的描述是:

换句话说,如果它是由一个空格分隔的单词,则将其与下一个单词分开;如果它在括号中,则拆分括号中的所有单词并删除它们。逗号也是同样的道理。

我猜你用逗号指的是引号 == 引用标记。
那么根据这个规则:
strs = "Hello (Test1 test2) (Hello1 hello2) other_stuff"

你应该理解那个。
["Hello (Test1 test2) (Hello1 hello2) other_stuff"]

由于所有内容都被引号包围,因此最可能的情况是您想在不考虑最大的引号的情况下进行工作。

我建议这样做,尽管有点丑陋的机器人。

import re, itertools
strs = raw_input("enter a string list ")

print [ y for y in list(itertools.chain(*[re.split(r'\"(.*)\"', x) 
        for x in re.split(r'\((.*)\)', strs)])) 
        if y <> '']

gets

>>> 
enter a string list here there (x y ) thereagain "there there"
['here there ', 'x y ', ' thereagain ', 'there there']

是的,对于逗号和引号以及我的措辞不太好的事实,我很抱歉,那是一个漫长的夜晚。上面的代码除了一件事之外都可以很好地工作,就是我在这里试图解释的“换句话说,如果它是由一个空格分隔的一个单词,那么它应该从下一个单词中分割出来”的部分,应该被分成两个不同的单词'here'和'there',而不是'hear there'。 - TrevorPeyton

1
这是按照您的期望执行的。
import re, itertools
strs = raw_input("enter a string list ")

res1 = [ y for y in list(itertools.chain(*[re.split(r'\"(.*)\"', x) 
        for x in re.split(r'\((.*)\)', strs)])) 
        if y <> '']

set1 = re.search(r'\"(.*)\"', strs).groups()
set2 = re.search(r'\((.*)\)', strs).groups()

print [k for k in res1 if k in list(set1) or k in list(set2) ] 
   + list(itertools.chain(*[k.split() for k in res1 if k 
   not in set1 and k not in set2 ]))

几乎可以,但它会打乱列表的顺序。例如,如果我输入 new word test (test1 test2) word word "test1 test2 tet3" te st,输出结果是 ['test1 test2', 'test1 test2 tet3', 'new', 'word', 'test', 'word', 'word', 'te', 'st'],几乎正确,但新单词的位置不对。 - TrevorPeyton
抱歉,我错了,顺序实际上很重要。 - kiriloff
我以为这是理所当然的,下次我会具体说明。这段代码有简单的修复方法吗? - TrevorPeyton

0

对于Python 3.6 - 3.8

我有一个类似的问题,但是我不喜欢那些答案,可能是因为大部分都是2013年的。所以我自己提出了一个解决方案。

regex = r'\(.+?\)|".+?"|\w+' 
test = 'Hello Test (Test1 test2) (Hello1 hello2) other_stuff'
result = re.findall(regex, test)

在此,您正在寻找三个不同的组:

  1. 包含在()内的内容;括号应与反斜杠一起书写
  2. 包含在""内的内容
  3. 只有单纯的词语
  4. 使用?使您的搜索变为惰性而非贪婪

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