I'm attempting to create a javascript function that will take an input, count the characters before a piece of content surrounded by square brackets and output the content above that line of the input with correct spacing based on the amount of characters leading up to that content. This project is to create music charts while being able to write the chords inline with the lyrics.
Example input:
This is a [G]lyric to a [C]song
I could [D]sing it all day [Em]long
Desired output:
G C
This is a lyrics to a song
D Em
I could sing it all day long
I'm not incredibly experienced with Javascript, but I know the basics. This project is just a little over my head. I've attached the code I have so far.
function processText(input) {
const lines = input.split("\n");
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() + "\n";
}
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);
I'm afraid my limited experience with JS has me at a standstill currently.
The current output of the code is
$ node test.js
G C
D Em
Which actually wouldn't be as problematic if the spacing was actually correct.. but I can't seem to get that right..
You can so something like this:
const input = `This is a [G]lyric to a [C]song
I could [D]sing it all day [Em]long`;
const output = input.split('\n').reduce((a, c) => {
const parts = c.split(/(\[[^\]]+\])/);
const lines = parts.reduce((acc, curr) => {
if (curr.startsWith('[') && curr.endsWith(']')) {
const cleanNote = curr.replace(/[[\]]/g, '');
const offset = acc.lyrics.length - acc.notes.length + cleanNote.length;
acc.notes += cleanNote.padStart(offset, ' ');
} else {
acc.lyrics += curr;
}
return acc;
}, { notes: '', lyrics: ''});
a.push(lines.notes);
a.push(lines.lyrics);
return a;
}, []).join('\n');
console.log(output);
What this does, is to first split the input into lines. Then, reduce those lines to generate an array of alternating notes and lyrics.
How that is done is to split each line so it will separate it into an array of lyrics and notes (c.split(/(\[[^\]]+\])/)
).
That array is then reduced to an object that has as properties notes
and lyrics
which are strings.
To calculate the offset, you can simply subtract the current length of the notes line from the current length of the lyrics line add add to that the length of the note (acc.lyrics.length - acc.notes.length + cleanNote.length
).