从 ArrayList 中提取 Java 字符串数据并使用 I/O 文件对其进行操作

Abstracting Java Strings data from ArrayList and manipulating it using I/O files

我是初学者。我正在尝试学习 1) 从文件中读取数据并存储在 ArrayList 中 2) 处理字符串数据 3) 使用 ArrayList 将结果输出到新文件。我已经弄清楚第 1 部分和第 3 部分,并提供了代码。我在处理字符串时遇到问题。我确信有一个更简单的解决方案,但即使花了很多时间我也看不到它。我知道我需要使用 charAt(i) 或 note.substring() 或两者。也许是嵌套循环?

// Part 1 Reading notes from a file and storing it into ArrayList named list.
    BufferedReader bufReader = new BufferedReader(new FileReader("read1.txt"));
    List<String> list = new ArrayList<>();
    String line = bufReader.readLine();
    while (line != null) {
        list.add(line);
        line = bufReader.readLine();
    }
    bufReader.close();
    list.forEach(System.out::println);//Print list to the Screen

    read1.txt  file   
    E  F#G# F#G# E   EF#D# E C#    E D# C# BB  C#C#
    C# E F# G# G# BAAG#   C# E F# G# C# B A G#

    May have lyrics here which needs to be avoided
    C# E G# C# B A G# G# B A G# F# A F# B G# F# D#

第 2 部分 这是我遇到问题的地方。 list[0] 有许多不同的音符,有和没有#。我如何用“,”分隔每个音符,所以结果看起来像下面这样。我想保持格式不变。我不想删除空格。

    E,  F#,G#, F#,G#, E,   E,F#,D#, E, C#,    E, D#, C#, B,B,  C#,C#
    C#, E, F#, G#, G#, B,A,A,G#,   C#, E, F#, G#, C#, B, A, G#,

    May have lyrics here which needs to be avoided
    C#, E, G#, C#, B, A, G#, G#, B, A, G#, F#, A, F#, B, G#, F#, D#

我想将以上结果存储到另一个名为 printToFile 的 ArrayList 中,我想使用以下代码输出结果。

//PART 3 This code will write List to a desired new file(write2.txt)
    List<String> printToFile = new ArrayList<>();
    //here We are assuming that results have been populated into printToFile
    BufferedWriter bufWriter = new BufferedWriter(new FileWriter("write2.txt"));

    for (String wline : printToFile) {
        bufWriter.write(wline);
        bufWriter.newLine();
    }
    bufWriter.close();

谁能教我怎么做第 2 部分。我已经测试了第 1 部分和第 3 部分。他们工作。对我来说,这是一个学习教程,所以我会欢迎不同的建议和想法。谢谢

您可以尝试 replaceAll 使用正则表达式来替换每个音符 [A-G],然后是可选的 # 并删除结尾的逗号:

String line = "E  F#G# F#G# E   EF#D# E C#    E D# C# BB  C#C#";
String str = line.replaceAll("([A-G]#?)", ",");
if (str.endsWith(",")) {
    str = str.substring(0, str.length() - 1);
}
System.out.println(line);
System.out.println(str);

输出:

E  F#G# F#G# E   EF#D# E C#    E D# C# BB  C#C#
E,  F#,G#, F#,G#, E,   E,F#,D#, E, C#,    E, D#, C#, B,B,  C#,C#

注意:如果输入数据包含其他类型的注释flatsharp,正则表达式需要相应更新。

更新
更高级的正则表达式可以在除最后一个音符之外的每个音符后正确插入逗号(无需使用附加代码删除尾随逗号)。

String str2 = line.replaceAll("([A-G]#?+(?!$))", ",");
System.out.println(str2);

([A-G]#?+(?!$)):

  • 第一个捕获组([A-G]#?+(?!$))
    • 匹配下面列表中的单个字符 [A-G]
      A-G A(索引 65)和 G(索引 71)之间范围内的单个字符(区分大小写)
    • #?+ 按字面匹配字符 #(区分大小写)
      ?+ 量词——在零到一次之间匹配,尽可能多次,不回馈(占有)
    • 负前瞻(?!$)
      断言下面的正则表达式不匹配
      $ 断言行尾的位置

online demo

可能还需要验证给定的输入字符串是否看起来像一串音符,然后应用此修改以避免在歌词中可能出现的 single-letter 个单词后插入逗号。

匹配的正则表达式是:^(\s*[A-G]#?\s*)+$ - 它检查是否至少有一个音符被可选的空格包围 \s*

所以,最终的解决方案如下:

private static String insertCommasIfLineOfNotes(String line) {
    if (null == line || !line.matches("^(\s*[A-G]#?\s*)+$")) {
        return line;
    }
    return line.replaceAll("([A-G]#?+(?!$))", ",");
}
// test
List<String> lines = Arrays.asList(
        "E  F#G# F#G# E   EF#D# E C#    E D# C# BB  C#C#", 
        "A Perfect Day Elise",
        "A B C D E F G H I J K L M N O P"
);
lines.stream()
     .map(MyClass::insertCommasIfLineOfNotes)
     .forEach(System.out::println);

// output
E,  F#,G#, F#,G#, E,   E,F#,D#, E, C#,    E, D#, C#, B,B,  C#,C#
A Perfect Day Elise
A B C D E F G H I J K L M N O P

更新 2
如果需要获取注释行中的子字符串列表,包含普通注释 A..G 可选地后跟 #,或 1 个或多个空格的序列,以下方法可以实现。
重构以将空白序列添加到适当的音符条目以方便将音符连接成单个字符串

private static List<String> buildListOfNotes(String line) {
    if (null == line || !line.matches("^(\s*[A-G]#?\s*)+$")) {
        return Arrays.asList(line); // for lyrics line
    }
    List<String> result = new ArrayList<>();
      
    int spaceStart = -1;
    int spaceEnd = 0;
    for(int i = 0; i < line.length() - 1; i++) {
        char c = line.charAt(i);
        boolean note = isNote(c);
        
        if (isNote(c)) {
            String prefix = "";
            if (spaceStart > -1) {
                // add existing whitespace as a prefix to current note
                int prevResult = result.size() - 1;
                prefix = line.substring(spaceStart, spaceEnd);
                spaceStart = -1;
            }
            if (line.charAt(i + 1) == '#') {
                result.add(prefix + line.substring(i, i + 2));
                i++;
            } else {
                result.add(prefix + line.substring(i, i + 1));
                if (!isNote(line.charAt(i + 1))) {
                    spaceStart = i + 1;
                }
            }
        } else {
            if (spaceStart == -1) {
                spaceStart = i;
                spaceEnd = i + 1;
            } else {
                spaceEnd++;
            }
        }
      }
      if (spaceStart > -1) {
          // add trailing whitespace if available to the last note
          int prevResult = result.size() - 1;
          result.set(prevResult, result.get(prevResult) + line.substring(spaceStart));
      }
      return result;
  }
  
  private static boolean isNote(char c) {
      return c >= 'A' && c <= 'G';
  }
// testing method to retrieve list of substring
List<String> lines = Arrays.asList(
        "E  F#G# F#G# E   EF#D# E C#    E D# C# BB  C#C#",
        "E  F#G# F#G# E   EF#D# E C#    E D# C# BB  C#C#    ",
        "   E  F#G# F#G# E   EF#D# E C#    E D# C# BB  C#C",
        "   E  F#G# F#G# E   EF#D# E C#    E D# C# BB  C#C ", 
        "A Perfect Day Elise",
        "A B C D E F G H I J K L M N O P"
);
lines.stream()
     .map(MyClass::buildListOfNotes)
     .forEach(System.out::println);

测试输出(“注意”条目可能包含空格序列):

[E,  F#, G#,  F#, G#,  E,   E, F#, D#,  E, C#,     E, D#,  C#,  B, B, C#, C#]
[E,  F#, G#,  F#, G#,  E,   E, F#, D#,  E, C#,     E, D#,  C#,  B, B, C#, C#    ]
[   E,  F#, G#,  F#, G#,  E,   E, F#, D#,  E, C#,     E, D#,  C#,  B, B, C#]
[   E,  F#, G#,  F#, G#,  E,   E, F#, D#,  E, C#,     E, D#,  C#,  B, B, C#, C ]
[A Perfect Day Elise]
[A B C D E F G H I J K L M N O P]

然后可以使用 String.join:

轻松地将音符数组转换为字符串
// lineToWrite will contain original whitespaces
String lineToWrite = String.join(",", buildListOfNotes(line));

// cleanLine will contain notes without extra spacing
String cleanLine = buildListOfNotes(line).stream()
                                         .map(String::trim)
                                         .collect(Collectors.joining(", "));