匹配某个单词后面的内容,用于正则表达式的一行代码?

5

我想从这样的列表中提取歌曲名:'some text here, songs: song1, song2, song3, fro: othenkl',并获取['song1', 'song2', 'song3']。因此我尝试用一个正则表达式完成:

result =  re.findall('[Ss]ongs?:?.*', 'songs: songname1, songname2,')
print re.findall('(?:(\w+),)*', result[0])

这完全匹配:['', '', '', '', '', '', '', '歌曲名1', '', '歌曲名2', ''](除了空字符串,但不要紧)。
但我想在一行中完成,所以我做了以下操作:
print re.findall('[Ss]ongs?:?(?:(\w+),)*','songs: songname1, songname2,')

但我不明白为什么这不能像上述两个正则表达式一样捕获相同的内容:

['', 'name1', 'name2']

有没有一种方法可以用一行代码完成这个任务?在这里简明扼要很有用。谢谢。
2个回答

2
不,你不能使用re模块中的一个模式来完成它。 你可以使用正则表达式模块,并使用以下模式:
regex.findall(r'(?:\G(?!\A), |\msongs: )(\w++)(?!:)', s)

其中,\G 表示上一个匹配之后的位置,\A 表示字符串的开头,\m 表示单词边界后面跟着单词字符,++ 表示占有量词。


2
在这种情况下,您不需要使用re.findall,最好使用re.search查找歌曲序列,然后使用逗号,分隔结果。此外,您不需要使用字符类[Ss]来匹配大写字母,可以使用忽略大小写标志(re.I):
>>> s ='some text here, songs: song1, song2, song3, fro: othenkl'
>>> re.search(r'(?<=songs:)(.+),', s,flags=re.I).group(1).split(',')
[' song1', ' song2', ' song3']

(?<=songs:)是一个正向预查,它会使你的正则表达式引擎匹配以songs:为前缀的字符串,并且(.+),将匹配在songs:之后跟随逗号的最长字符串,即你的歌曲序列。

此外,与其在正则表达式末尾指定逗号,还可以根据歌曲名称后面紧随这个模式\s\w+:来捕获歌曲名称,这是一种更通用的方法。

>>> re.search(r'(?<=songs:)(.+)(?=\s\w+:)', s).group(1).split(',')
[' song1', ' song2', ' song3', '']

所以,我猜你仍然在进行两步操作,尽管它只有一行代码。因为你仍然需要通过split(',')search的结果中分离出来。 - makansij
请注意,如果捕获组没有找到任何匹配项,则此操作将失败:re.search(...)将返回None,对于上述表达式将不再有意义。 - normanius

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