How to replace multiple substrings with different substrings?

I have this chord string obtained from a text file. For instance,

String chordLine = "CG Am C"; String transposedChordLine; 

Then I need to transfer the chordLine to a new transposedChordLine , using the following class, using two parameters, a String chord and an integer transposition increment. For example, transpose("C", 2) will return D

  public class Transposer{ private int inc; private static ArrayList<String> keysSharp; private static ArrayList<String> keysFlat; Transposer(){ keysSharp = new ArrayList<String>(Arrays.asList("C", "C#", "D", "D#","E", "F","F#", "G","G#", "A","A#", "B")); keysFlat = new ArrayList<String>(Arrays.asList("C", "Db", "D", "Eb","E", "F","Gb", "G","Ab", "A","Bb", "B")); } public String transpose(String chord,int inc){ this.inc = inc; String newChord; if(chord.contains("/")){ String[] split = chord.split("/"); newChord = transposeKey(split[0]) + "/" + transposeKey(split[1]); }else newChord = transposeKey(chord); return newChord; } private String transposeKey(String key){ // C#m/D# must pass C#m or D# String nKey, tempKey; if(key.length()>1){ nKey = key.substring(0, 2); } else{ nKey = key; } int oldIndex, newIndex; if(key.contains("b")){ oldIndex = (keysFlat.indexOf(nKey)>-1) ? keysFlat.indexOf(nKey) : keysFlat.indexOf(similarKey(nKey)); newIndex = (oldIndex + inc + keysFlat.size())%keysFlat.size(); tempKey = keysFlat.get(newIndex); nKey = (key.length() < 3) ? tempKey : key.replace(nKey, tempKey); //(nKey + key.substring(nKey.length(), key.length())); } else if(key.contains("#")){ oldIndex = (keysSharp.indexOf(nKey)>-1) ? keysSharp.indexOf(nKey) : keysSharp.indexOf(similarKey(nKey)); newIndex = (oldIndex + inc + keysSharp.size())%keysSharp.size(); tempKey = keysSharp.get(newIndex); nKey = (key.length() < 3) ? tempKey : key.replace(nKey, tempKey); } else{ nKey = nKey.substring(0, 1); oldIndex = (keysSharp.indexOf(nKey)>-1) ? keysSharp.indexOf(nKey) : keysSharp.indexOf(similarKey(nKey)); newIndex = (oldIndex + inc + keysSharp.size())%keysSharp.size(); tempKey = keysSharp.get(newIndex); nKey = (key.length() < 2) ? tempKey : key.replace(nKey, tempKey); } return nKey; } private String similarKey(String nKey) { String newKey; switch(nKey){ case "Cb": newKey = "B"; break; case "Fb": newKey = "E"; break; case "E#": newKey = "F"; break; case "B#": newKey = "c"; break; default: newKey = null; } return newKey; } } 

How to replace chordLine without losing spaces? increment by 2 must have transposedChordLine="DA Bm D"

Here is my current attempt:

 public static void main(String[] args) { String chordLine = "CG Am C"; String transposedChordLine; String normalize = chordLine.replaceAll("\\s+", " "); String[] split = normalize.split(" "); //System.out.println(normalize); Transposer tran = new Transposer(); String[] temp = new String[split.length]; for(int i=0 ; i<split.length ; i++){ temp[i] = tran.transpose(split[i], 2); //System.out.println(split[i]); System.out.print(temp[i]); } transposedChordLine = chordLine.replaceAll([split], temp); //which is wrong } 
+5
source share
3 answers

Your tokenism is quite unusual (with separators preserved) that you probably want to do it yourself. Basically, if you see a token corresponding to a note, pass it to the transponder. Otherwise, follow the space bar. Use the while loop to move through notes. Here is the code that does just that:

 private static final Transposer transposer = new Transposer(); public static void main(String[] args) { String chordLine = "CG Am C"; String transposed = transposeChordLine(chordLine); System.out.println(transposed); } private static String transposeChordLine(String chordLine) { char[] chordLineArray = chordLine.toCharArray(); StringBuilder transposed = new StringBuilder(); StringBuilder currentToken = new StringBuilder(); int index = 0; while(index < chordLine.length()) { if(chordLineArray[index] == ' ') { transposed.append(' '); currentToken = processToken(transposed, currentToken); } else { currentToken.append(chordLineArray[index]); } index++; } processToken(transposed, currentToken); return transposed.toString(); } private static StringBuilder processToken(StringBuilder transposed, StringBuilder currentToken) { if(currentToken.length() > 0) { String currentChord = currentToken.toString(); String transposedChord = transposer.transpose(currentChord, 2); transposed.append(transposedChord); currentToken = new StringBuilder(); } return currentToken; } 

Note. You have some stylistic issues with your code. You can initialize your permanent chord cards in the fields themselves; By doing this in the constructor, you overwrite them, do unnecessary work, and potentially cause problems, especially in multi-threaded code. Just make them inline in the field declaration. It is also useful to wrap them in Collections.unmodifiableList , so they cannot be changed when your code runs, and therefore facilitate a random error.

In addition, you should not store the inc variable in the field, just pass it as an argument. Thus, if you use the same object twice, it does not save state and therefore is thread safe. I know that it does not matter for your current program, but it’s good to learn these habits now. Here's the Transposer class changed:

 public class Transposer { private static final List<String> keysSharp = Collections.unmodifiableList(Arrays.asList("C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B")); private static final List<String> keysFlat = Collections.unmodifiableList(Arrays.asList("C", "Db", "D", "Eb", "E", "F", "Gb", "G", "Ab", "A", "Bb", "B")); public String transpose(String chord, int inc) { String newChord; if (chord.contains("/")) { String[] split = chord.split("/"); newChord = transposeKey(split[0], inc) + "/" + transposeKey(split[1], inc); } else newChord = transposeKey(chord, inc); return newChord; } private String transposeKey(String key, int inc) { // C#m/D# must pass C#m or D# String nKey, tempKey; if (key.length() > 1) { nKey = key.substring(0, 2); } else { nKey = key; } int oldIndex, newIndex; if (key.contains("b")) { oldIndex = (keysFlat.indexOf(nKey) > -1) ? keysFlat.indexOf(nKey) : keysFlat.indexOf(similarKey(nKey)); newIndex = (oldIndex + inc + keysFlat.size()) % keysFlat.size(); tempKey = keysFlat.get(newIndex); nKey = (key.length() < 3) ? tempKey : key.replace(nKey, tempKey); // (nKey + key.substring(nKey.length(), key.length())); } else if (key.contains("#")) { oldIndex = (keysSharp.indexOf(nKey) > -1) ? keysSharp.indexOf(nKey) : keysSharp.indexOf(similarKey(nKey)); newIndex = (oldIndex + inc + keysSharp.size()) % keysSharp.size(); tempKey = keysSharp.get(newIndex); nKey = (key.length() < 3) ? tempKey : key.replace(nKey, tempKey); } else { nKey = nKey.substring(0, 1); oldIndex = (keysSharp.indexOf(nKey) > -1) ? keysSharp.indexOf(nKey) : keysSharp.indexOf(similarKey(nKey)); newIndex = (oldIndex + inc + keysSharp.size()) % keysSharp.size(); tempKey = keysSharp.get(newIndex); nKey = (key.length() < 2) ? tempKey : key.replace(nKey, tempKey); } return nKey; } private String similarKey(String nKey) { String newKey; switch (nKey) { case "Cb": newKey = "B"; break; case "Fb": newKey = "E"; break; case "E#": newKey = "F"; break; case "B#": newKey = "c"; break; default: newKey = null; } return newKey; } } 
+1
source

Here's a shorter solution (I added this method to the Transposer class):

 public String transposeLine(String chordLine, int inc) { Pattern pattern = Pattern.compile("\\S+\\s*"); // can be moved to static final field Matcher matcher = pattern.matcher(chordLine); StringBuffer sb = new StringBuffer(); while(matcher.find()) { String chord = matcher.group(); String transposed = transpose(chord.trim(), inc); matcher.appendReplacement(sb, String.format(Locale.ENGLISH, "%-"+chord.length()+"s", transposed)); } matcher.appendTail(sb); return sb.toString(); } 

I use regex to create a new line. The regular expression matches the name of the chord along with all spaces after that. To ensure that the substitution is the same length, I use String.format and provide a format string, such as %-XXs , where XX is the length of the non-transposed chord with spaces. Please note: if there are not enough spaces, the resulting line becomes longer.

Using:

 public static void main(String[] args) { String chordLine = "CG Am C"; System.out.println(chordLine); for(int i=0; i<12; i++) { String result = new Transposer().transposeLine(chordLine, i); System.out.println(result); } } 

Output:

 CG Am C CG Am C C# G# A#m C# DA Bm D D# A# Cm D# EBC#m E FC Dm F F# C# D#m F# GD Em G G# D# Fm G# AEF#m A A# F Gm A# BF# G#m B 
+1
source

For a chord string, transposer, and increment to transpose:

 String chordLine = "CG Am C"; Transposer tran = new Transposer(); int offset = 2; 

To get the transposed chord line while maintaining a space, you can use regular search expressions up to split at the boundaries of the spaces, then conditionally process the resulting lines through your transposer, as follows:

 String transposed = Arrays.stream(chordLine.split("((?<=\\s)|(?=\\s))")).map( // use regex to split on every whitespace boundary str -> // for each string in the split Character.isWhitespace(str.charAt(0)) // if the string is whitespace ? str // then keep the whitespace : tran.transpose(str, offset) // otherwise, it a chord, so transpose it ).collect(Collectors.joining()); // re-join all the strings together 

Or, if you prefer Java 7, use StringBuilder to plot the transposed chord line when you StringBuilder over the tokens:

 StringBuilder sb = new StringBuilder(); for (String str : chordLine.split("((?<=\\s)|(?=\\s))")) { sb.append(Character.isWhitespace(str.charAt(0)) ? str : tran.transpose(str, offset)); } String transposed = sb.toString(); 
0
source

All Articles