我正在尝试匹配包含和弦的行,但我需要确保每个匹配都被空格包围或排在第一行而不会消耗字符,因为我不希望它们返回给调用者。
E.g。
Standard Tuning (Capo on fifth fret)
Time signature: 12/8
Tempo: 1.5 * Quarter note = 68 BPM
Intro: G Em7 G Em7
G Em7
I heard there was a secret chord
G Em7
That David played and it pleased the lord
C D G/B D
But you don't really care for music, do you?
G/B C D
Well it goes like this the fourth, the fifth
Em7 C
The minor fall and the major lift
D B7/D# Em
The baffled king composing hallelujah
Chorus:
G/A G/B C Em C G/B D/A G
Hal - le- lujah, hallelujah, hallelujah, hallelu-u-u-u-jah ....
除了它之外几乎可以匹配“68 BPM”中的“B”。现在我如何确保和弦正确匹配?我不希望它与之前的B或SUBSIDE中的D或E匹配吗?
这是我在每个单独行上匹配的算法:
function getChordMatches(line) {
var pattern = /[ABCDEFG](?:#|##|b|bb)?(?:min|m)?(?:maj|add|sus|aug|dim)?[0-9]*(?:\/[ABCDEFG](?:#|##|b|bb)?)?/g;
var chords = line.match(pattern);
var positions = [];
while ((match = pattern.exec(line)) != null) {
positions.push(match.index);
}
return {
"chords":chords,
"positions":positions
};
}
那就是我想要表格[“A”,“Bm”,“C#”]上的数组,而不是[“A”,“Bm”,“C#”]。
修改
我使用接受的答案使其工作。我不得不做一些调整以适应领先的空白。感谢大家花时间!
function getChordMatches(line) {
var pattern = /(?:^|\s)[A-G](?:##?|bb?)?(?:min|m)?(?:maj|add|sus|aug|dim)?[0-9]*(?:\/[A-G](?:##?|bb?)?)?(?!\S)/g;
var chords = line.match(pattern);
var chordLength = -1;
var positions = [];
while ((match = pattern.exec(line)) != null) {
positions.push(match.index);
}
for (var i = 0; chords && i < chords.length; i++) {
chordLength = chords[i].length;
chords[i] = chords[i].trim();
positions[i] -= chords[i].length - chordLength;
}
return {
"chords":chords,
"positions":positions
};
}
答案 0 :(得分:1)
我假设您已将输入拆分为行。该函数将逐个处理这些行。
在提取它们之前,你只需要检查该行是否有一个和弦作为第一项:
if (/^\s*[A-G](?:##?|bb?)?(?:min|m)?(?:maj|add|sus|aug|dim)?[0-9]*(?:\/[A-G](?:##?|bb?)?)?(?!\S)/.test(line)) {
// Match the chords here
}
我在前面添加^\s*
以从行的开头进行检查,并添加(?!\S)
以检查第一个和弦后面是否有空白字符\s
或行尾。
请注意,我对您的正则表达式进行了一些小的更改,因为A##
(假设它是有效的和弦)将不会与您当前的正则表达式匹配。正则表达式引擎将按照交替模式的顺序检查匹配,因此#
将首先在#|##
中尝试A#
。它会发现##
匹配并返回匹配而不检查##|#
。撤消订单##?
或使用贪婪量词line.split(/\s+/);
可以解决问题,因为它会先检查更长的备选方案。
如果你确定:“如果第一项是和弦,那么其余的是和弦”,那么你可以用空格分开而不是匹配:
/(?:^|\s)[A-G](?:##?|bb?)?(?:min|m)?(?:maj|add|sus|aug|dim)?[0-9]*(?:\/[A-G](?:##?|bb?)?)?(?!\S)/
<强>更新强>
如果你想匹配你的模式,无论和弦是否在句子内(你现在拥有的是什么):
(?:^|\s)
此正则表达式将放在您问题中的代码中。
我检查和弦前面是空白字符,或者是\b
行的开头。但是,您需要修剪结果中的前导空格。
使用(?:^|\s)
代替\s+
将避免引发空间问题,但意义不同。除非你足够了解输入,否则我会反对它。
另一种方法是将字符串拆分为^
,并针对每个令牌测试以下正则表达式(注意开头的$
和结尾的 /^[A-G](?:##?|bb?)?(?:min|m)?(?:maj|add|sus|aug|dim)?[0-9]*(?:\/[A-G](?:##?|bb?)?)?$/
):< / p>
{{1}}
答案 1 :(得分:0)
在开始和结束时添加\b
(单词边界)对我有用。此外,您可以使用A-G
代替ABCDEFG
。因此:
> re = /\b[A-G](?:#|##|b|bb)?(?:min|m)?(?:maj|add|sus|aug|dim)?[0-9]*(?:\/[A-G](?:#|##|b|bb)?)?\b/g
/\b[A-G](?:#|##|b|bb)?(?:min|m)?(?:maj|add|sus|aug|dim)?[0-9]*(?:\/[A-G](?:#|##|b|bb)?)?\b/g
> 'G/A G/B C Em C G/B D/A G'.match(re)
["G/A", "G/B", "C", "Em", "C", "G/B", "D/A", "G"]
> 'Tempo: 1.5 * Quarter note = 68 BPM'.match(re)
null
答案 2 :(得分:0)
在回答标题中的具体问题时,请使用前瞻:
(?=\s)
当嵌入RE时,将确保后续字符是空白而不消耗它。
答案 3 :(得分:0)
尝试以下
function getChordMatches( line ) {
var match,
pattern = /(?:^|\s)([A-G](?:##?|bb?)?(?:min|m)?(?:maj|add|sus|aug|dim)?\d*(?:\/[A-G](?:##?|bb?)?)?)(?=$|\s)/g,
chords = [],
positions = [];
while ( match = pattern.exec(line) ) {
chords.push( match[1] );
positions.push( match.index );
}
return {
"chords" : chords,
"positions" : positions
};
}
它使用(?:^|\s)
来确保和弦位于行的开头或前面有空格,并使用正向前瞻(?=$|\s)
来确保和弦后跟一个空间或位于线的末端。添加括号以捕获和弦本身,然后由match[1]
访问。