标准吉他歌词/和弦括号的正则表达式

7
我正在尝试在标准文本文档中添加方括号以围绕吉他/歌词和弦,以使它们更符合OnSong应用程序的要求。我有规则但不知道如何匹配所有可能的组合。这些规则是:
  • 和弦将以一个大写字母A-G开头
  • 如果大写A-G后面跟着一个空格、断行、#、b、m、sus、aug、dim、maj、min或/,我想读取到下一个空格或断行(由于标准吉他格式,像F#min /E这样的和弦是可能的,而我只想一直读到空格,而不想麻烦地分割)
  • 如果大写A-G后跟着另一个不在上述列表中的字母,则正则表达式不应匹配(例如名称“Ed”不应匹配)
  • 如果你能找出如何使“一片小小世界”由于后面的单词不是有效的和弦而不匹配,则可以额外得分。
  • 如果替换可以删除新括号前面的空格(当不是在行首时)和括号后面的空格(以保持对齐),则可以超级加分。 - 有人指出这会在关闭和弦上失败... 这是完全可以接受的。

一些注意事项:这是一个辅助脚本...不需要完美。我现在手动完成这个操作,所以偶尔会有错误。我并不试图分析和弦的细节,只是将它们包裹在[]中。虽然标准布局是1行和弦,1行歌词,但不能保证,因此我知道有些情况会偶尔失败。

测试源(为了测试目的,和弦是随机的,以防任何音乐家对可怕的音乐发表意见):

Db    Dsus4/F#           A            Cbmin/C
A man can't be asked for that much to do
D/F#        G         A           D#/E
And I can't sweep you off of your feet

Should turn into:

[Db]  [Dsus4/F#]         [A]          [Cbmin/C]
A man can't be asked for that much to do
[D/F#]      [G]       [A]         [D#/E]
And I can't sweep you off of your feet

我第一次尝试接近成功:

([A-G]((?!\s).)*)

但它也会选择以这些字母开头的单词。我现在已经转了一圈,只得到了如下结果:
\b([CDEFGAB](#|##|b|bb|sus|maj|min|aug)?\b)

当我尝试使用[^\s+]时,结果千差万别,有时会获取更多我需要的内容,但也会遗漏必要的内容。我觉得这是自己超出了能力范围。非常感谢任何帮助,并且更好的解释它的工作原理将不胜感激。虽然我想要一个解决方案,但我也真的很想知道为什么它有效...


那么 A# Eb // Oh man! 将变成 [A#][Eb] // Oh man!?由于这些和弦的接近,我们失去了对齐(添加括号)。 - zessx
关于和弦彼此紧贴的好处,你说得很对...有时候它们的对齐就是无法实现--我已经接受了这个命运 :) - IglooWhite
你会使用哪种语言或工具来使用正则表达式?这个动物是什么? - Casimir et Hippolyte
没有特定的语言...计划只是制作一个小型shell脚本或微型Java应用程序来处理文本文件。例如,这是吉他手/歌手常见的歌曲格式。歌词上方有基本和弦。我还使用一款用于现场演出的应用程序,可以读取文本文件,但如果和弦被括起来,它将把它们转换成实际的和弦图表,这非常有用。问题是,对于成千上万的歌曲文件,添加括号变得繁琐。(示例链接) http://tabs.ultimate-guitar.com/p/pearl_jam/alive_crd.htm - IglooWhite
5个回答

7

这个示例输入经过测试通过,并且满足您所有的“超级奖励分”要求:

String output = input.replaceAll("(?m)(^| )([A-G](##?|bb?)?((sus|maj|min|aug|dim)\\d?)?(/[A-G](##?|bb?)?)?)( (?!\\w)|$)", "[$2]");

这段代码将会把这个字符串(作为一个带有嵌入式行费的单个字符串)转化为:
Db    Dsus4/F#           A            Cbmin/C
A man can't be asked for that much to do
D/F#        G         A           D#/E
And I can't sweep you off of your feet

转化为这样:

[Db]  [Dsus4/F#]         [A]          [Cbmin/C]
A man can't be asked for that much to do
[D/F#]      [G]       [A]         [D#/E]
And I can't sweep you off of your feet

非常酷 - 目前它没有保持对齐吗? - IglooWhite
不 - 从输出可以看出,整个和弦行在开头插入[后向右移动了一个字符。为了避免这种情况,需要在行首的和弦后面消耗额外的空格(即2个空格)。虽然说实话,现在使用[标记和弦的开头看起来很好 - 可以直接使用它。顺便说一下,您可能会发现Apache commons-io FileUtils.readFileToString()writeStringToFile()很方便。 - Bohemian
我正在尝试在R中实现这个..但是我无法让它工作。我的regex101示例会抛出一个错误/ An unescaped delimiter must be escaped with a backslash (\) https://regex101.com/r/3NbIwi/1 - Ratnanil
@Ratnanil 在正则表达式中,反斜杠字符没有特殊含义,但许多编程语言使用正斜杠来分隔正则表达式,我猜测 R 语言也是如此。请尝试在我的正则表达式中每个正斜杠前面加上一个反斜杠。如果这不起作用,请尝试在每个正斜杠前面加上双反斜杠。 - Bohemian

4

我改进了之前答案中的一些内容,以适应我的情况。现在,当它在诗歌的开头时(如A、E),它会忽略一些"和弦可能性"。

(\(*[CDEFGAB](?:b|bb)*(?:#|##|sus|maj|min|aug|m|M|°|[0-9])*[\(]?[\d\/]*[\)]?(?:[CDEFGAB](?:b|bb)*(?:#|##|sus|maj|min|aug|m|M|°|[0-9])*[\d\/]*)*\)*)(?=[\s|$])(?! [a-z])

3

看看这个:

/([A-G](#|b)?)(\(?(M|maj|major|m|min|minor|dim|sus|dom|aug)?(\+|-|add)?\d*\)?)(\/([A-G](#|b)?))?/g

我从 chord-transposer 中获取了它:

var XRegExp = require("xregexp");

// Chromatic scale starting from C using flats only.
var FLAT_SCALE = ["C", "Db", "D", "Eb", "E", "F", "Gb", "G", "Ab", "A", "Bb", "Cb"];

// Chromatic scale starting from C using sharps only.
var SHARP_SCALE = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"];

// Regex for recognizing chords
var ROOT_PATTERN = '(?<root>[A-G](#|b)?)';

var SUFFIX_PATTERN = '(?<suffix>\\(?(M|maj|major|m|min|minor|dim|sus|dom|aug)?(\\+|-|add)?\\d*\\)?)';

var BASS_PATTERN = '(\\/(?<bass>[A-G](#|b)?))?';

var MINOR_PATTERN = '(m|min|minor)+';

var CHORD_REGEX = XRegExp("^" + ROOT_PATTERN + SUFFIX_PATTERN + BASS_PATTERN + "$");

然后

console.log(CHORD_REGEX); // will output regexp mentioned at the beginning of the answer

对我来说它很有效。


3

我已经为你提供了一些适用于你所提供的情况的正则表达式,但无法确定它对其他情况是否适用。问题在于一行可以以A开头,或者可以在歌词行中。我尝试使用负向预查来解决这个问题,检查和弦后面是否跟着一个空格和一个字母数字字符。如果有空格和字母数字字符,则不匹配此和弦。由于和弦可以在/之后重复,所以我将模式加倍。

\b([CDEFGAB](?:b|bb)*(?:#|##|sus|maj|min|aug)*[\d\/]*(?:[CDEFGAB](?:b|bb)*(?:#|##|sus|maj|min|aug)*[\d\/]*)*)(?=\s|$)(?! \w)

请查看演示


这真是太棒了。我也加入了我忘记的'm'选项。(?<=\b)([CDEFGAB](?:b|bb|m)*(?:#|##|sus|maj|min|aug)*[\d\/]*(?:[CDEFGAB](?:b|bb|m)*(?:#|##|sus|maj|min|aug)*[\d\/]*)*)(?=\s|$)(?! \w) - IglooWhite
请注意,如果和弦之间只有一个空格,则可能会出现问题。也许,我们可以通过使用 (?! [^ CDEFGAB]) 前瞻来使其更安全。 - Wiktor Stribiżew
FYI,“(?<=\b)”与“\b”完全相同,因为两者都不会消耗输入。此外,这将匹配“Aaugmin”或A#######-请改用?而不是*。 - Bohemian

0

在我检查的样本中,该代码很好地执行了协议,并且与C# 7等带有升降号的协议一样简单明了。

string strRegex = @"^[A-G]([5679bm#]([57])?|1[13]|6\/9|7[-#+b][59]|7?sus[24]|add[249]|aug|dim7?|m\/maj7|m1[13]|m[679]|m7?b5|maj1[13]|maj[79])?([\/][A-G]([5679bm#])?([57])?)?";

Regex myRegex = new Regex(strRegex, RegexOptions.None);
string strTargetString = @"A";
string strReplace = @"[$0]";

return myRegex.Replace(strTargetString, strReplace);

请注意,这是一个 Java 问题。 - Bohemian
@Eric 奇怪的是,另一个用户将Java加入了混合中,因为我的问题实际上是一个通用的正则表达式问题。我意识到最后的替换需要选择一种语言,但任何一种语言都可以做到。话虽如此,我认为这过于复杂化了真正的需求...因为我并不想证明无效的和弦(dim35或类似的东西),所以在这里进行了很多额外的检查。如果有人要解析细节,这可能会非常有用。 - IglooWhite

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