Henk Rensenbrink
Henk Rensenbrink

Reputation: 87

Replace multiple character with javascript

Currently I am replacing just a character with something different, as it is a music sheet that needs to be altered the character might differ. Therefore I created a JavaScript code which will replace all these letters if on the sheet.

Here the problem occurs, If I have character A which needs to be replaced with C and later on in the same JavaScript code C needs to be replaced with D. Therefore A changes to D instead of C. I need every character replaced once per action instead of comparing the replaced text with other possibilities.

Here is my code so far:

function Dkoord() {
  $('[id^=harm] > text:nth-child(1) > tspan:nth-child(1)').text(function(i, text) {
    return text.replace('A', 'B').replace('A#', 'C').replace('Bb', 'C')
               .replace('B', 'C#').replace('C', 'D').replace('C#', 'D#')
               .replace('Db', 'Eb').replace('D', 'E').replace('D#', 'F')
               .replace('Eb', 'F').replace('F', 'G').replace('F#', 'G#')
               .replace('Gb', 'Ab').replace('G', 'A').replace('G#', 'A#')
               .replace('Ab', 'Bb');
});
}

As you can see C is changing to D but later on changing the D to E, I just want a character to be compared once. How do I do this.

Upvotes: 2

Views: 115

Answers (3)

nnnnnn
nnnnnn

Reputation: 150070

Use one regular expression to match what you want to replace, something like this:

/[A-G](b|#)?/g

That is, match any letters from A-G, optionally followed by b or #.

Then use .replace() with a callback to lookup what was matched and return the appropriate replacement.

function Dkoord() {
  var replacements = {
      'A': 'B', 'A#': 'C', 'Bb': 'C', 'B': 'C#', 'C': 'D', 'C#': 'D#',
      'Db': 'Eb', 'D': 'E', 'D#': 'F', 'Eb': 'F', 'F': 'G', 'F#': 'G#',
      'Gb': 'Ab', 'G': 'A', 'G#': 'A#', 'Ab': 'Bb'
  };

  $('[id^=harm] > text:nth-child(1) > tspan:nth-child(1)').text(function(i, text) {
    return text.replace(/[A-G](b|#)?/g, function(m) { return replacements[m]; });
  });
}

Expand and run the following snippet for a simplified demo:

function Dkoord(text) {
  var replacements = {
      'A': 'B', 'A#': 'C', 'Bb': 'C', 'B': 'C#', 'C': 'D', 'C#': 'D#',
 	  'Db': 'Eb', 'D': 'E', 'D#': 'F', 'Eb': 'F', 'F': 'G', 'F#': 'G#',
	  'Gb': 'Ab', 'G': 'A', 'G#': 'A#', 'Ab': 'Bb'
  };
    	  
  return text.replace(/[A-G](b|#)?/g, function(m) { return replacements[m]; });
}

console.log(Dkoord("A# B C D/F# G A"))

Note that using a lookup object like that also has the advantage that you could extend it to have more than one object to allow for transposing into different keys. For example, if transposing from B major to C# you should change D# into E#, but if transposing from F# major to Ab you should change D# into F.

Upvotes: 5

Chris
Chris

Reputation: 59541

One easy way of doing this would be to replace the initial value with a temporary one and then replacing the temporary variable again.

For example:

function Dkoord() {
  $('[id^=harm] > text:nth-child(1) > tspan:nth-child(1)').text(function(i, text) {
    return text.replace('A', 'b').replace('A#', 'c').replace('Bb', 'c')
               .replace('B', 'c#').replace('C', 'd').replace('C#', 'd#')
               .replace('Db', 'e_').replace('D', 'e').replace('D#', 'f')
               .replace('Eb', 'f').replace('F', 'g').replace('F#', 'g#')
               .replace('Gb', 'a_').replace('G', 'a').replace('G#', 'a#')
               .replace('Ab', 'b_').toUpperCase().replace(/[_]/g, "b");
  });
}

This will replace the text you want with the "correct" value in lowercase, this will prevent the next pipe from replacing the already replaced value.

Once done, you can go through your string and simply set everything back to uppercase. So just add this after your last replace.

.toUpperCase().replace(/[_]/g, "b");

Obviously, you can use any character(s) you wish, as long as it is unique.

Demo

$("#btn").on("click", function() {
  $("#demo").text(function(i, text) {
    return text.replace('A', 'b').replace('A#', 'c').replace('Bb', 'c')
      .replace('B', 'c#').replace('C', 'd').replace('C#', 'd#')
      .replace('Db', 'e_').replace('D', 'e').replace('D#', 'f')
      .replace('Eb', 'f').replace('F', 'g').replace('F#', 'g#')
      .replace('Gb', 'a_').replace('G', 'a').replace('G#', 'a#')
      .replace('Ab', 'b_').toUpperCase().replace(/[_]/g, "b");
  });
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<b id="demo">AC#Eb</b>
<button id="btn">Convert</button>

Upvotes: 2

Try something like this

 function Dkoord() {

     $('[id^=harm] > text:nth-child(1) > tspan:nth-child(1)').text(function(i, text) {

      return text.replace('Ab', 'Bb').replace('G#', 'A#').replace('G', 'A')
            .replace('Gb', 'Ab').replace('F#', 'G#').replace('F', 'G')
            .replace('Eb', 'F').replace('D#', 'F').replace('D', 'E')
            .replace('Db', 'Eb').replace('C#', 'D#').replace('C', 'D')
            .replace('B', 'C#').replace('Bb', 'C').replace('A#', 'C')
            .replace('A', 'B')
 });
 }

Upvotes: 0

Related Questions