Reputation: 87
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
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
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.
$("#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
Reputation: 334
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