如何用不同的子串替换多个子串?

时间:2015-08-17 05:29:37

标签: java string replace

我从文本文件中获得了这一和弦。例如,

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

接下来,我需要使用下面的类使用两个参数chordLine和弦以及转置的整数增量将transposedChordLine转置为新的String。例如,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

}

3 个答案:

答案 0 :(得分: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 :(得分: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。正则表达式匹配和弦名称以及之后的所有空格。为了确保替换具有相同的长度,我使用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

答案 2 :(得分:0)

给定和弦线,转置器以及转置增量:

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

要在保留空格的同时获得转置的和弦线,您可以在空白边界使用regular expression lookaroundssplit,然后通过转置符有条件地处理生成的字符串,如下所示:

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