英文:
Abstracting Java Strings data from ArrayList and manipulating it using I/O files
问题
// PART 2: Separating musical notes and formatting
String notesLine = list.get(0); // Get the line with musical notes
String[] notesArray = notesLine.split("\\s+"); // Split by whitespace
List<String> formattedNotes = new ArrayList<>(); // To store the formatted notes
for (String note : notesArray) {
if (!note.isEmpty()) { // Avoid empty strings
formattedNotes.add(note + ","); // Add note with a comma
}
}
// Combine the formatted notes into a single string
String formattedNotesLine = String.join(" ", formattedNotes);
// Add the formatted line to the printToFile ArrayList
printToFile.add(formattedNotesLine);
请注意,上述代码段是关于如何完成第二部分的解释和示例代码,这部分将音符分隔并进行格式化,以满足您的要求。将此代码段添加到您的项目中,确保与您的现有代码协同工作,并根据需要进行适当的调整。
请注意,由于您要求我只返回翻译好的部分,我已经从您的原始内容中提取了您想要的内容并进行了翻译。如果您有任何问题,欢迎随时提问。
英文:
I am a beginner. I am trying to learn 1) Read data from a file and store inside ArrayList 2) Manipulate String data 3) Output results to a new file using ArrayList. I have figured out Part 1 and Part 3 and I have provided the code. I am having problems manipulating strings. I am sure there is an easier solution but I am not able to see it even after spending many hours. I know I need to use either charAt(i) or note.substring() or both. Maybe a nested loop?
// 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#
PART 2 This is where I'm having a problem. list[0] has many different musical notes with and without #. How do I sperate each note with "," so result would look something like following. I want to keep the format same. I don't want to remove the whitespaces.
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#
I want to store above result into another ArrayList named printToFile and I want to output the result using following code.
//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();
Can someone pls teach me how to do Part2. I have tested Part1 and Part3. They work. For me, this is a learning tutorial so I will WELCOME different suggestions and ideas. Thanks
答案1
得分: 2
// 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(", "));
英文:
You may try replaceAll
with a regular expression to replace each note [A-G]
followed by optional #
and removing trailing comma:
String line = "E F#G# F#G# E EF#D# E C# E D# C# BB C#C#";
String str = line.replaceAll("([A-G]#?)", "$1,");
if (str.endsWith(",")) {
str = str.substring(0, str.length() - 1);
}
System.out.println(line);
System.out.println(str);
Output:
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#
note: if the input data contain other types of notes flat
or sharp
, the regular expression needs to be updated accordingly.
update<br/>
More advanced regular expression enables proper insertion of commas after each note except the last one (without removal of the trailing comma with additional code).
String str2 = line.replaceAll("([A-G]#?+(?!$))", "$1,");
System.out.println(str2);
([A-G]#?+(?!$))
:
- 1st Capturing Group
([A-G]#?+(?!$))
- Match a single character present in the list below
[A-G]
<br/>
A-G
a single character in the range betweenA
(index 65) andG
(index 71) (case sensitive) #?+
matches the character#
literally (case sensitive)<br/>
?+
Quantifier — Matches between zero and one times, as many times as possible, without giving back (possessive)- Negative Lookahead
(?!$)
<br/>
Assert that the Regex below does not match<br/>
$
asserts position at the end of a line
- Match a single character present in the list below
It also may be needed to verify if the given input string looks like a string of notes and then apply this modification to avoid inserting commas after single-letter words which might happen in the lyrics.
The matching regular expression is: ^(\s*[A-G]#?\s*)+$
- it checks if there is at least one note surrounded with optional whitespaces \s*
.
So, the final solution would look like:
private static String insertCommasIfLineOfNotes(String line) {
if (null == line || !line.matches("^(\\s*[A-G]#?\\s*)+$")) {
return line;
}
return line.replaceAll("([A-G]#?+(?!$))", "$1,");
}
// 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
update 2<br/>
If it is needed to get a list of substrings in the line of notes, containing plain notes A
..G
optionally followed by #
, or sequences of 1 or more whitespaces, the following methods can be implemented.<br/>
refactored to add whitespace sequences to appropriate note entry to facilitate joining of the notes into single string
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);
Test output ("note" entry may include whitespace sequence):
[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]
Then the array of notes can be easily converted into String using 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(", "));
</details>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论