2015-08-17 124 views
5

我有從文本文件中獲得的這一行和絃。例如,如何用不同的子字符串替換多個子字符串?

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

接下來,我需要用下面用兩個參數,轉置的String弦和整數增量類移調chordLine到一個新的transposedChordLine。例如,transpose("C", 2)將返回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; 
    } 
} 

如何在不損失空間的情況下更換chordLine? 增量2應該有transposedChordLine="D A Bm D"

這裏是我當前的嘗試:

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

很多潛在的解決方案。例如:創建一個對象,即「ChordLine」,它將實例化單個和絃線。在這個對象的構造函數中,你可以顯式地跟蹤和絃'n_i'和'n_i + 1'之間的空白量。然後,在換位時,您可以簡單地替換輸出中的空白'ChordLine' – Kon

+0

對不起,這不是關於你的問題,而是你的代碼非常糟糕。不要在構造函數中初始化靜態成員。將這兩個靜態變爲'List ',並使用'Arrays.asList'直接初始化它們。另外,不要使用實例字段將參數傳遞給私有方法。如果'inc'在調用'transpose'時可能不同,則將其作爲參數傳遞給私有方法。如果'inc'始終是相同的,則將其傳遞給構造函數,而不是'transpose'方法。 – Andreas

+0

大約一年前我開始使用java。感謝您的評論。 – Tuss

回答

1

你的符號化是不尋常的足夠(保留分隔符),你可能想自己做。基本上,如果您看到與筆記匹配的標記,請將其傳遞給轉碼器。否則,傳遞一個空間。使用while循環沿着音符導航。下面是做到了這一點代碼:

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

注意:你有一些文體的問題與您的代碼。您可以在字段本身初始化您的恆定和絃地圖;通過在構造函數中這樣做,可以覆蓋它們,進行不必要的工作並可能導致問題,特別是在多線程代碼中。只需在現場聲明中進行內聯。將它們封裝在Collections.unmodifiableList中也是很好的,所以當你的代碼運行時它們不能被改變,因此它更容易不會意外地出錯。

此外,您不應將inc變量保存在字段中,只需將其作爲參數傳遞即可。這樣,如果您使用同一個對象兩次,它不會保留狀態,因此是線程安全的。我知道這些對你目前的課程無關緊要,但現在學習這些習慣是很好的。下面是修改後的Transposer類:

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

這裏的短溶液(我加了這個方法的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(); 
} 

我使用正則表達式匹配來創建新的字符串。正則表達式匹配和絃名稱以及之後的所有空格。爲了確保替換具有相同的長度,我使用String.format並提供格式字符串,如%-XXs,其中XX是帶空格的非轉置和絃的長度。請注意,如果沒有足夠的空間,則生成的線會變長。

用法:

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

輸出:

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

鑑於絃線,換位和增量移調:

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

要獲得換位絃線,同時保留您可以在whitespace bou上使用regular expression lookaroundssplit ndaries,然後有條件地處理通過您的換位生成的字符串,如下所示:

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 

或者如果你喜歡的Java 7,使用StringBuilder建立換位絃線,你遍歷令牌:

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(); 
相關問題