如何按括号外的逗号分割字符串?
我有一个这样的字符串:
"Wilbur Smith (Billy, son of John), Eddie Murphy (John), Elvis Presley, Jane Doe (Jane Doe)"
基本上这是一个演员名字的列表(后面可以跟着他们的角色,用括号表示)。角色本身可以包含逗号(但演员的名字应该不能有逗号,我希望是这样)。
我的目标是把这个字符串拆分成一对对的形式——(演员名字, 演员角色)
。
一个明显的解决办法是逐个字符检查,看看有没有出现'('
、')'
和','
,然后在逗号出现的地方进行拆分。但这样做似乎有点复杂……
我在想能不能用正则表达式来拆分:先通过括号来拆分这个字符串:
import re
x = "Wilbur Smith (Billy, son of John), Eddie Murphy (John), Elvis Presley, Jane Doe (Jane Doe)"
s = re.split(r'[()]', x)
# ['Wilbur Smith ', 'Billy, son of John', ', Eddie Murphy ', 'John', ', Elvis Presley, Jane Doe ', 'Jane Doe', '']
这里的奇数位置是演员名字,偶数位置是角色。然后我可以通过逗号来拆分名字,想办法提取出名字和角色的配对。但这样似乎比我第一种方法还要复杂。
有没有更简单或者更好的方法来做到这一点,或者用一个正则表达式,或者写一段好看的代码?
10 个回答
我觉得处理这个问题最好的方法是使用Python自带的 csv 模块。
因为csv模块只允许使用一个字符作为 quotechar
,所以你需要先把输入中的 ()
替换成其他符号,比如 |
或 "
。然后确保你使用了合适的方言(dialect),这样就可以开始了。
s = re.split(r',\s*(?=[^)]*(?:\(|$))', x)
这个前瞻匹配的是从当前位置到下一个开括号或者字符串的结尾,前提是中间没有闭括号。这样可以确保逗号不在括号里面。
一种方法是使用 findall
和一个贪婪匹配的正则表达式,这个表达式可以匹配分隔符之间的内容。比如:
>>> s = "Wilbur Smith (Billy, son of John), Eddie Murphy (John), Elvis Presley, Jane Doe (Jane Doe)"
>>> r = re.compile(r'(?:[^,(]|\([^)]*\))+')
>>> r.findall(s)
['Wilbur Smith (Billy, son of John)', ' Eddie Murphy (John)', ' Elvis Presley', ' Jane Doe (Jane Doe)']
上面的正则表达式可以匹配一个或多个:
- 不是逗号,也不是左括号的字符
- 以左括号开头,里面可以有0个或多个不是右括号的字符,最后以右括号结束的字符串
这种方法的一个特点是,相邻的分隔符会被当作一个分隔符来处理。也就是说,你不会看到空字符串。这可能在某些情况下是个缺陷,也可能是个优点,具体要看你的需求。
另外要注意,正则表达式 不适合 用于可能有嵌套的情况。所以比如说,这样的情况会分割得不对:
"Wilbur Smith (son of John (Johnny, son of James), aka Billy), Eddie Murphy (John)"
如果你需要处理嵌套,最好的办法是先把字符串分成括号、逗号和其他所有内容(基本上就是把它们分开处理——这部分仍然可以用正则表达式来做),然后再逐个处理这些部分,重新组合字段,同时记录你的嵌套层级(这个记录嵌套层级的过程是正则表达式无法单独完成的)。