所以我在解析文本时遇到了问题。我试图解析音乐文件,它们是半格式化的。例如,我试图从歌词中排除合唱。大多数情况下,格式如下:
[Chorus: x2] Some Lyrics Some More Lyrics [Verse] Lyrics Lyrics
在这种情况下,这两个函数可以正确解析:
subChorus = re.sub(r'\[Chorus.*?\].*?\[', '[', lyrics, flags = re.DOTALL);
subChorus2 = re.sub(r'\[Chorus.*?\].*?(\n{2,})', '', lyrics, flags = re.DOTALL);
但是,偶尔合唱是文件的最后一部分:
Lyrics [Chorus] Some Lyrics Other Lyrics
在这种情况下,我无法找出正确的表达方式来删除合唱。如果我只是做
subChorusEnd = re.sub(r'\[Chorus.*?\].*?$', '', lyrics, flags = re.DOTALL);
它会起作用;但是,对于最终合唱部分不在最后的其他文件,它将删除需要保留的经文。所有带有以下经文的合唱块都至少由两个换行符分隔。所以我提出了这个解决方案:
subChorusEnd = re.sub(r'\[Chorus.*?\][^(\n{2,})]*?$', '', subChorus4, flags = re.DOTALL);
但它不起作用。有人可以向我解释正确的正则表达式,以使上述语句工作或更好的方法,只删除位于文本部分末尾的合唱块,这也将保留最终合唱不在最后的文件
答案 0 :(得分:1)
您可以尝试使用以下正则表达式匹配所有Chorus块。
\[Chorus.*?\].*?(\n{2,}|$)
OR
(?!.*\n\n)\[Chorus.*?\].*?$
它仅匹配最后的chorus
块。不要忘记在两个正则表达式中启用DOTALL修饰符。
答案 1 :(得分:0)
我不想使用正则表达式,而是逐行逐步翻阅歌词,并决定是否使用基本上是一个糟糕的有限状态机来保持每一行:
lyrics1 = '''Lyrics
[Chorus]
Some Lyrics
Other Lyrics'''
lyrics2 = '''[Chorus: x2]
Some Lyrics
Some More Lyrics
[Verse]
Lyrics
Lyrics'''
def clean(lyrics):
result = []
omitting = False
for line in lyrics.split('\n'):
if '[Chorus' in line:
omitting = True
if '[' in line and '[Chorus' not in line:
omitting = False
if not omitting:
result.append(line)
return '\n'.join(result)
print(clean(lyrics1))
print('------------')
print(clean(lyrics2))
结果:
Lyrics
------------
[Verse]
Lyrics
Lyrics
所以基本上,如果我们看到" Chorus"线和停止输出线;然后,如果我们看到任何括号内的东西不是" Chorus",我们将旗帜翻转并恢复输出线。
我不知道您正在解析的实际文件是什么样的,但是这样的策略可能比投入庞大的正则数据更有效。
答案 2 :(得分:0)
\[Chorus:[^\]]+\][\s\S]*?(?=\n{2}|$)
尝试使用empty string
所有类型的合唱。请参阅演示。