2015-08-17 2 views
5

Ich habe diese Akkordlinie aus Textdatei erhalten. Zum BeispielWie ersetze ich mehrere Teilstrings durch verschiedene Teilstrings?

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

Als nächstes muss ich unter Verwendung von zwei Parametern, ein String Akkord und integer Zuwachs von transponieren die chordLine in eine neue transposedChordLine mit der Klasse transponieren. Zum Beispiel gibt transpose("C", 2) zurück.

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; 
    } 
} 

Wie ersetze ich die chordLine ohne die Leerzeichen zu verlieren? Zuwachs von 2 sollte transposedChordLine="D A Bm D"

Hier mein aktueller Versuch ist:

public static void main(String[] args) { 

    String chordLine = "C  G   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 

} 
+1

Viele mögliche Lösungen. Zum Beispiel: Erstellen Sie ein Objekt, 'ChordLine', das eine einzelne Akkordlinie einspielt. In diesem Konstruktor des Objekts können Sie explizit die Menge an Leerzeichen zwischen den Akkorden 'n_i' und' n_i + 1' verfolgen. Dann können Sie beim Transponieren einfach den Leerraum im Ausgang 'ChordLine' ersetzen. – Kon

+0

Entschuldigung, es geht nicht um Ihre Frage, aber Ihr Code ist wirklich schlecht. Initialisieren Sie nicht 'statische' Member im Konstruktor. Ändern Sie die beiden Statiken in 'List ' und initialisieren Sie diese direkt mit 'Arrays.asList'. Verwenden Sie keine Instanzfelder, um Parameter an private Methoden zu übergeben. Wenn "inc" bei Aufrufen von "transpose" unterschiedlich sein kann, dann übergeben Sie es als Parameter an die privaten Methoden. Wenn "inc" immer gleich ist, übergeben Sie es an den Konstruktor und nicht an die transpose-Methode. – Andreas

+0

Ich habe gerade vor etwa einem Jahr mit Java angefangen. Danke für den Kommentar. – Tuss

Antwort

1

Ihre tokenization ungewöhnlich genug ist (Konservieren Begrenzer), dass Sie wahrscheinlich, es selbst tun mögen. Wenn Sie ein Token sehen, das mit einer Notiz übereinstimmt, übergeben Sie es im Grunde an den Transponierer. Andernfalls passiere ein Leerzeichen. Verwenden Sie eine while-Schleife, um entlang der Notizen zu navigieren. Hier ist der Code, der genau das tut:

private static final Transposer transposer = new Transposer(); 

public static void main(String[] args) { 
    String chordLine = "C  G   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; 
} 

Hinweis: Sie haben einige stilistische Probleme mit Ihrem Code. Sie können Ihre konstanten Akkordkarten in den Feldern selbst initialisieren; Wenn Sie dies im Konstruktor tun, überschreiben Sie sie, tun unnötige Arbeit und verursachen möglicherweise Probleme, insbesondere in Multithread-Code. Mach sie einfach inline in der Felddeklaration. Es ist auch gut, diese in Collections.unmodifiableList zu verpacken, damit sie nicht geändert werden können, wenn der Code ausgeführt wird, und es daher einfacher macht, nicht versehentlich einen Fehler zu machen.

Außerdem sollten Sie die inc Variable nicht in einem Feld speichern, sondern nur als Argument übergeben. Wenn Sie das gleiche Objekt zweimal verwenden, behält es den Zustand nicht bei und ist daher threadsafe. Ich weiß, dass diese Dinge für dein aktuelles Programm keine Rolle spielen, aber es ist gut, diese Gewohnheiten jetzt zu lernen. Hier ist die modifizierte Transposer Klasse:

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

Hier kürzere Lösung (I hinzugefügt, um diese Methode auf die Transposer Klasse):

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(); 
} 

Ich bin mit Regex Matcher den neuen String zu erstellen. Der reguläre Ausdruck stimmt mit dem Akkordnamen und allen darauf folgenden Leerzeichen überein. Um sicherzustellen, dass der Ersatz die gleiche Länge hat, verwende ich String.format und stelle Formatstring wie %-XXs zur Verfügung, wobei XX die Länge des nicht transponierten Akkords mit Leerzeichen ist. Beachten Sie, dass die resultierende Zeile länger wird, wenn nicht genügend Leerzeichen vorhanden sind.

Verbrauch:

public static void main(String[] args) { 
    String chordLine = "C  G   Am  C"; 

    System.out.println(chordLine); 
    for(int i=0; i<12; i++) { 
     String result = new Transposer().transposeLine(chordLine, i); 
     System.out.println(result); 
    } 
} 

Ausgang:

C  G   Am  C 
C  G   Am  C 
C#  G#   A#m  C# 
D  A   Bm  D 
D#  A#   Cm  D# 
E  B   C#m  E 
F  C   Dm  F 
F#  C#   D#m  F# 
G  D   Em  G 
G#  D#   Fm  G# 
A  E   F#m  A 
A#  F   Gm  A# 
B  F#   G#m  B 
0

eine Sehnenlinie, Transposer gegeben, und ein Zuwachs für die Umsetzung:

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

die transponierte Sehnenlinie zu erhalten, während der Erhaltung Leerraum, können Sie regular expression lookarounds bis split bei Leerzeichen Bou verwenden ndaries, dann verarbeiten bedingt die resultierenden Strings durch Ihre Transposer, wie folgt:

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's a chord, so transpose it 
).collect(Collectors.joining());             // re-join all the strings together 

Oder wenn Sie Java bevorzugen 7, verwenden Sie einen StringBuilder die transponierte Sehnenlinie zu bauen, wie Sie die Token iterieren:

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();