2015-08-17 29 views
5

Ho questa linea di accordi ottenuta dal file di testo. Ad esempio,Come sostituire più sottostringhe con sottostringhe diverse?

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

Successivamente, ho bisogno di trasporre la chordLine in una nuova transposedChordLine utilizzando la classe di seguito utilizzando due parametri, un String corda e intero incremento di trasposizione. Ad esempio, transpose("C", 2) restituirà 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; 
    } 
} 

Come sostituire lo chordLine senza perdere gli spazi? incremento del 2 dovrebbe avere transposedChordLine="D A Bm D"

Ecco il mio tentativo in corso:

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

Un sacco di soluzioni potenziali. Ad esempio: crea un oggetto, 'ChordLine' che istanzia una singola linea di accordi. Nel costruttore di questo oggetto è possibile tenere esplicitamente traccia della quantità di spazio bianco tra gli accordi 'n_i' e' n_i + 1'. Quindi, al momento della trasposizione, puoi semplicemente sostituire lo spazio bianco nell'output 'ChordLine' – Kon

+0

Scusa, non si tratta della tua domanda, ma il tuo codice è davvero pessimo. Non inizializzare i membri 'static' nel costruttore. Cambia le due statiche in 'Lista ' e inizializzale direttamente usando 'Arrays.asList'. Inoltre, non utilizzare i campi di istanza per passare i parametri ai metodi privati. Se 'inc' può essere diverso nelle chiamate a' transpose', quindi passalo come parametro ai metodi privati. Se 'inc' è sempre lo stesso, passalo sul costruttore, non sul metodo' transpose'. – Andreas

+0

Ho iniziato java circa un anno fa. Grazie per il commento. – Tuss

risposta

1

tuo tokenizzazione è insolito sufficiente (delimitatori conservanti), che, probabilmente, si vuole farlo da soli. Fondamentalmente, se vedi un token che corrisponde a una nota, passalo al transposer. Altrimenti, passa lungo uno spazio. Usa un ciclo while per navigare lungo le note. Ecco il codice che fa proprio questo:

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

Nota: avete alcune questioni stilistiche con il codice. Puoi inizializzare le tue mappe di accordi costanti nei campi stessi; così facendo nel costruttore, le sovrascrivi, esegui il lavoro non necessario e potenzialmente causando problemi, specialmente nel codice multithread. Basta farli in linea nella dichiarazione di campo. È anche consigliabile avvolgerli in Collections.unmodifiableList, in modo che non possano essere modificati quando il codice è in esecuzione e quindi rende più facile non commettere accidentalmente un errore.

Inoltre, non si deve salvare la variabile inc in un campo, basta passarla come argomento. In questo modo, se si utilizza lo stesso oggetto due volte, non viene mantenuto lo stato ed è quindi protetto da thread. So che queste cose non sono importanti per il tuo programma attuale, ma è bello imparare queste abitudini ora. Ecco la modifica Transposer classe:

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

Ecco la soluzione più breve (ho aggiunto questo metodo per la classe Transposer):

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

sto usando Matcher regex per creare la nuova stringa. L'espressione regolare corrisponde al nome dell'accordo insieme a tutti gli spazi successivi. Per garantire che la sostituzione abbia la stessa lunghezza, utilizzo String.format e fornisco una stringa di formato come %-XXs dove XX è la lunghezza dell'accordo non trasposto con gli spazi. Notare che se non ci sono spazi sufficienti, la linea risultante si allunga.

Usage:

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

uscita:

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

Data una linea di corda, transposer, e un incremento per il recepimento:

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

per ottenere la linea di corda trasposto preservando spazio bianco, è possibile utilizzare regular expression lookarounds a split in spazio bianco bou ndaries, poi condizionalmente elaborare le stringhe risultanti attraverso il vostro transposer, come segue:

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 

Oppure, se preferite Java 7, utilizzare un StringBuilder per costruire la linea di corda trasposto come eseguire iterazioni sui gettoni:

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