求助:JavaScript实现歌词和弦对应排版的代码问题
问题描述
需要编写一个JavaScript函数,接收包含方括号包裹和弦的歌词输入,统计和弦前方的字符数量,将和弦输出在对应歌词行的上方,并根据前置字符数设置正确的间距,生成和弦与歌词对齐的乐谱。
示例输入:
This is a [G]lyric to a [C]song I could [D]sing it all day [Em]long
期望输出:
G C This is a lyric to a song D Em I could sing it all day long
现有代码仅输出和弦行且间距错误,无法实现需求:
function processText(input) { const lines = input.split(" "); let output = ""; for (let line of lines) { let startIndex = line.indexOf("["); let endIndex = line.indexOf("]", startIndex); let lastIndex = 0; let lineOutput = ""; while (startIndex !== -1 && endIndex !== -1) { const padding = startIndex - lastIndex; const content = line.substring(startIndex + 1, endIndex); lineOutput += " ".repeat(padding); lineOutput += content + " "; lastIndex = endIndex + 1; line = line.substring(endIndex + 1); startIndex = line.indexOf("["); endIndex = line.indexOf("]", startIndex); } lineOutput += line.substring(lastIndex); output += lineOutput.trim() + " "; } return output; } const input = `This is a [G]lyric to a [C]song I could [D]sing it all day [Em]long`; const output = processText(input); console.log(output);
当前输出:
G C D Em
问题分析
现有代码存在以下核心问题:
- 仅生成和弦行,未保留去除和弦后的原歌词行,导致输出缺少关键内容。
- 循环中修改原
line变量,后续startIndex基于截断后的字符串计算,与原字符串索引错位,导致间距计算错误。 - 未考虑和弦被移除后歌词行的长度变化,无法正确对齐和弦与对应歌词位置。
修正后的代码
function processText(input) { // 按行分割并过滤空行 const lines = input.split('\n').filter(line => line.trim() !== ''); let output = ''; for (const originalLine of lines) { // 匹配所有[和弦]格式,获取内容与原位置 const chordMatches = [...originalLine.matchAll(/\[([^\]]+)\]/g)]; // 生成去除和弦的干净歌词行 const lyricLine = originalLine.replace(/\[([^\]]+)\]/g, ''); // 初始化和弦行:用空格填充至歌词行长度 let chordLine = ' '.repeat(lyricLine.length); // 逐个处理每个和弦,计算对齐位置 for (const match of chordMatches) { const chord = match[1]; // 原字符串中[的起始索引 const originalStartIndex = match.index; // 计算和弦在和弦行中的位置:减去前面所有[和弦]占用的3个字符长度 const previousChordsCount = chordMatches.indexOf(match); const chordPosition = originalStartIndex - previousChordsCount * 3; // 将和弦替换到对应位置 chordLine = chordLine.substring(0, chordPosition) + chord + chordLine.substring(chordPosition + chord.length); } // 若和弦行非空则添加,再添加歌词行 if (chordLine.trim() !== '') { output += chordLine + '\n'; } output += lyricLine + '\n'; } return output.trim(); } // 测试输入 const input = `This is a [G]lyric to a [C]song I could [D]sing it all day [Em]long`; const output = processText(input); console.log(output);
代码解释
- 匹配和弦:使用
matchAll正则匹配所有[和弦]格式的内容,同时获取每个和弦在原字符串中的起始索引,避免手动循环索引的错误。 - 生成歌词行:通过
replace移除所有[和弦]内容,得到干净的歌词行。 - 初始化和弦行:用与歌词行等长的空格填充,保证和弦行与歌词行的长度一致,基础对齐。
- 计算和弦位置:每个和弦的对齐位置 = 原字符串中的起始索引 - 前面已处理和弦的数量×3(每个
[和弦]占3个字符,移除后需修正位置)。 - 填充和弦:将和弦替换到和弦行的对应位置,实现精准对齐。
- 输出处理:过滤空行,避免多余内容;仅当和弦行非空时才添加,确保无和弦的行只输出歌词。
内容的提问来源于stack exchange,提问作者Aaron Phillips
相关产品推荐
相关产品推荐

