1

I have some lines of song lyric and chords, with format like below:

enter image description here

And need to convert just like below: enter image description here

I am able to get the chord keys, but getting trouble when trying to put them to each column on each line.

This is what I've done:

_read({required String text}) {
    var result = text.split('\n');

    RegExp re = RegExp(r"^[A-G\d#b\s/-/m]*$(?:\r\n)?", caseSensitive: false, multiLine: true);

    var chords = '';
    for (final i in re.allMatches(text)) {
      chords = '$chords\n${(i[0]) ?? ''}';
    }
    var arrChords = chords.split('\n');

    for (int j = 0; j < arrChords.length; j++) {
      final i = arrChords[j];
      print(i);

      if (i.isNotEmpty) {
        // I am stuck from here
        var lineChords = i.split(' ');

        for (int k = lineChords.length - 1; k > 0; k--) {
          final e = lineChords[k];
          if (e.isNotEmpty) {
            var sRight = result[j + 1].substring(k);
            var sLeft = result[j + 1].substring(0, k);
            print(sLeft + sRight);
            // result[j + 1] = '$sLeft[$e]$sRight';
          }
        }
      }
    }

    // return result;
  }

Edit : Answer/suggestion using C#, JS, or Dart are welcome

Fadhly Permata
  • 1,686
  • 13
  • 26

1 Answers1

1

Finally, I've been success to make it. Just want to share my final result, perhaps someone need it:

_read({required String text}) {
    RegExp re = RegExp(r"(\(*[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])");
    List<String> arrLyrics = <String>[];
    List<String> arrChords = <String>[];

    // take each chords and lyrics on each line positions
    for (var e in text.split('\n')) {
      if (e.isEmpty) {
        arrChords.add('');
        arrLyrics.add('');
      } else {
        if (re.allMatches(e).isEmpty) {
          arrLyrics.add(e);
          arrChords.add('');
        } else {
          arrChords.add(e);
          arrLyrics.add('');
        }
      }
    }

    for (int i = 0; i < arrChords.length; i++) {
      // take or skip on empty chord
      String sChords = arrChords[i];
      if (sChords.isEmpty || sChords.replaceAll(' ', '').isEmpty) continue;

      // if chords is found, but there are no lyric on next line then just write the chords
      String sLyric = arrLyrics[i + 1];
      if (sLyric.isEmpty || sLyric.replaceAll(' ', '').isEmpty) {
        arrLyrics[i] = sChords.split(' ').map((x) => '[$x]').where((x) => x.isNotEmpty).join(' ');
        continue;
      }

      // make sure we have equal width
      if (sLyric.length < sChords.length) {
        sLyric = sLyric.padRight(sChords.length);
      }

      int lastIndex = 0;
      String lyricAndChord = '';
      List<String> chords = sChords.split(' ').where((x) => x.isNotEmpty).toList();

      for (String chord in chords) {
        // get position of chord
        int iPos = sChords.indexOf(chord, lastIndex);

        // write compiled lyric and chords
        chord = '[$chord]';
        lyricAndChord += '${sLyric.substring(lastIndex, iPos)}$chord';
        lastIndex = iPos;
      }

      // make sure to take any last chars.
      lyricAndChord += sLyric.substring(lastIndex);

      arrLyrics[i + 1] = lyricAndChord;
    }
    return arrLyrics.join('\n').replaceAll('\n\n', '\n').trim();
}

Edit :

  • The snippet is only based on my need.
  • I found RegEx pattern for searching chord from here, and updated on the snippet.
Fadhly Permata
  • 1,686
  • 13
  • 26