Python RE。排除一些结果

时间:2019-02-22 14:53:13

标签: python regex

我是RE的新手,我想获取歌曲歌词并隔离诗歌标题,背景声和主要声。

这是一些歌词的例子:

[Intro]
D.A. got that dope!

[Chorus: Travis Scott]
Ice water, turned Atlantic (Freeze)
Nightcrawlin' in the Phantom (Skrrt, Skrrt)...

经文标题包括方括号和方括号之间的任何单词。可以使用

成功隔离它们
r'\[{1}.*?\]{1}'

背景音乐与诗歌标题相似,但在()之间。已通过以下方式成功隔离它们:

r'\({1}.*?\){1}'

对于主要人声,我已经使用

r'\S+'

确实隔离了main_vocals,但也隔离了诗句标题和辅助人声。我无法弄清楚如何用简单的RE仅隔离主要人声。

这是一个python脚本,可以获取我想要的输出,但是我想使用RE(作为学习练习)来完成此操作,并且无法通过文档来解决。

import re

file = 'D:/lyrics.txt'
with open(file, 'r') as f:
    lyrics = f.read()

def find_spans(pattern, string):
    pattern = re.compile(pattern)
    return [match.span() for match in pattern.finditer(string)]

verses = find_spans(r'\[{1}.*?\]{1}', lyrics)
backing_vocals = find_spans(r'\({1}.*?\){1}', lyrics)
main_vocals = find_spans(r'\S+', lyrics)

exclude = verses
exclude.extend(backing_vocals)

not_main_vocals = []
for span in exclude:
    start, stop = span
    not_main_vocals.extend(list(range(start, stop)))

main_vocals_temp = []
for span in main_vocals:
    append = True
    start, stop = span
    for i in range(start, stop):
        if i in not_main_vocals: 
            append = False
            continue
    if append == True: 
        main_vocals_temp.append(span)
main_vocals = main_vocals_temp

2 个答案:

答案 0 :(得分:1)

尝试以下Demo

pattern = r'(?P<Verse>\[[^\]]+])|(?P<Backing>\([^\)]+\))|(?P<Lyrics>[^\[\(]+)'

您可以使用re.finditer来隔离组。

breakdown = {k: [] for k in ('Verse', 'Backing', 'Lyrics')}
for p in pattern.finditer(song):
    for key, item in p.groupdict().items():
        if item: breakdown[key].append(item)

结果:

{
  'Verse': 
    [
      '[Intro]', 
      '[Chorus: Travis Scott]'
    ], 
  'Backing': 
    [
      '(Freeze)', 
      '(Skrrt, Skrrt)'
    ], 
  'Lyrics': 
    [
      '\nD.A. got that dope!\n\n', 
      '\nIce water, turned Atlantic ', 
      "\nNightcrawlin' in the Phantom ", 
      '...'
    ]
}

为了进一步详细说明模式,它使用命名组将三个不同的组分开。使用[^\]+]和类似方法意味着找到所有不是 ](同样,当\)意味着所有 not {{1 }})。在歌词部分,我们排除以)[开头的任何内容。 link to the demo on regex101将在需要时更详细地解释这些组件。

如果您不喜欢主歌词中的换行符,请使用((不包括(?P<Lyrics>[^\[\(\n]+))来使歌词不换行:

\n

答案 1 :(得分:1)

您可以使用正则表达式组在右括号和右括号之间搜索文本。如果您的正则表达式中有一个组(圆括号内的子模式),则re.findall将仅返回这些括号的内容。

例如,"\[(.*?)\]"只会找到部分标签,不包括方括号(因为它们不在组中)。

正则表达式"\)(.*?)\("仅找到最后一行(“幻影”​​中的“ \ nNightcrawlin'”)。
同样,我们可以在第一行找到"\](.*?)\["

将两种类型的方括号组合到一个字符类中,(看起来更加凌乱)正则表达式"[\]\)](.*?)[\[\(]"捕获了所有歌词。

它将错过在其之前或之后没有方括号的行(即,如果有,则在[简介]之前的最开始;如果其后没有支持人声,则在末尾)。可能的解决方法是在字符串的末尾添加“]”字符,并在末尾添加“ [”字符,以强制匹配在字符串的末尾开始/结束。请注意,我们需要添加DOTALL选项以确保通配符“。”将与换行符“ \ n”匹配

import re

lyrics = """[Intro]
D.A. got that dope!

[Chorus: Travis Scott]
Ice water, turned Atlantic (Freeze)
Nightcrawlin' in the Phantom (Skrrt, Skrrt)..."""


matches = re.findall(r"[\]\)](.*?)[\[\(]", "]" + lyrics + "[", re.DOTALL)
main_vocals = '\n'.join(matches)