Reputation: 616
I have a file called logfile.log. I want to sort the logfile.log by a substring (test name between two pipe characters) and direct the output to a file called sorted_logfile.log
CURRENT logfile.log:
2020-05-09 05:51:13,985 INFO | CreateCardTest| : -> some message
2020-05-09 05:51:13,985 INFO | WorkspaceTest| : -> some message
2020-05-09 05:51:14,779 INFO | WorkspaceTest| : -> some message
2020-05-09 05:51:14,779 INFO | CreateCardTest| : -> some message
2020-05-09 05:51:14,779 INFO | WorkspaceTest| : -> some message
2020-05-09 05:51:14,779 INFO | SavedTest| Leads : -> some message
2020-05-09 05:51:14,779 INFO | WorkspaceTest| : some message
2020-05-09 05:51:14,780 INFO | WorkspaceTest| Workspace : some message
2020-05-09 05:51:15,732 INFO | CreateCardTest| Leads : -> some message
2020-05-09 05:51:15,732 INFO | WorkspaceTest| Workspace : some message
2020-05-09 05:51:21,638 INFO | SavedTest| Leads : -> some message
2020-05-09 05:51:21,638 INFO | CreateCardTest| Leads : -> some message
2020-05-09 05:51:21,653 INFO | WorkspaceTest| Workspace : Accounts,All Accounts : -> some message
2020-05-09 05:51:21,653 INFO | WorkspaceTest| Workspace : Accounts,All Accounts : -> some message
2020-05-09 05:51:21,803 INFO | WorkspaceTest| Workspace : Accounts,All Accounts : -> some message
2020-05-09 05:51:21,803 INFO | CreateCardTest| Leads : -> some message
'CreateCardTest', 'WorkspaceTest' and 'SavedTest' are the test names. It is the substring between the two pipe characters based on which it needs to be sorted. Within the test, the messages should be in the same order (ordered by timestamp as in the current log file).
DESIRED sorted_logfile.log:
2020-05-09 05:51:13,985 INFO | CreateCardTest| : -> some message
2020-05-09 05:51:14,779 INFO | CreateCardTest| : -> some message
2020-05-09 05:51:15,732 INFO | CreateCardTest| Leads : -> some message
2020-05-09 05:51:21,638 INFO | CreateCardTest| Leads : -> some message
2020-05-09 05:51:21,803 INFO | CreateCardTest| Leads : -> some message
2020-05-09 05:51:14,779 INFO | SavedTest| Leads : -> some message
2020-05-09 05:51:21,638 INFO | SavedTest| Leads : -> some message
2020-05-09 05:51:13,985 INFO | WorkspaceTest| : -> some message
2020-05-09 05:51:14,779 INFO | WorkspaceTest| : -> some message
2020-05-09 05:51:14,779 INFO | WorkspaceTest| : -> some message
2020-05-09 05:51:14,779 INFO | WorkspaceTest| : some message
2020-05-09 05:51:14,780 INFO | WorkspaceTest| Workspace : some message
2020-05-09 05:51:15,732 INFO | WorkspaceTest| Workspace : some message
2020-05-09 05:51:21,653 INFO | WorkspaceTest| Workspace : Accounts,All Accounts : -> some message
2020-05-09 05:51:21,653 INFO | WorkspaceTest| Workspace : Accounts,All Accounts : -> some message
2020-05-09 05:51:21,803 INFO | WorkspaceTest| Workspace : Accounts,All Accounts : -> some message
Here is my current code:
public static void main(String[] args) {
BufferedReader reader;
try {
reader = new BufferedReader(new FileReader("log/logfile.log"));
String line = reader.readLine();
while (line != null) {
System.out.println(line);
// read next line
line = reader.readLine();
}
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
How do I achieve this? I have looked at Collections.sort() but that didn't work for substrings.
Upvotes: 0
Views: 187
Reputation: 103903
You can sort on a comparator; the comparator needs to be able to decree in a consistent fashion: Given any 2 objects, which one 'is higher'?
Also, note that main can just throws, so that cleans up your code, and FileReader
should never be used without specifying a charset unless you really, really, really know you want platform default (hint: you don't). On java8 this constructor does not exist, so there you can't use filereader at all.
public static void main(String[] args) throws Exception {
var lines = new ArrayList<String>();
try (BufferedReader br = new FileReader("log/logfile.log", StandardCharsets.UTF_8)) {
String line = br.readLine();
while (line != null) {
lines.add(line);
line = br.readLine();
}
}
lines.sort(Comparator.comparing(a -> textBetweenBars(a)));
}
public String textBetweenBars(String a) {
int idx1 = a.indexOf('|' + 1);
int idx2 = a.indexOf('|', idx1);
return a.substring(idx1, idx2);
// you may want to write some code on what to do if those bars aren't there...
}
or with new API a bit cleaner:
public static void main(String[] args) throws Exception {
var lines = Files
.readAllLines(Paths.get("log/logfile.log"))
.sort(Comparator.comparing(a -> textBetweenBars(a)));
}
public String textBetweenBars(String a) {
int idx1 = a.indexOf('|') + 1;
int idx2 = a.indexOf('|', idx1);
return a.substring(idx1, idx2);
// you may want to write some code on what to do if those bars aren't there...
}
NB: The various string-reading/writing methods in the Files class default to UTF-8 whereas most other things (including FileReader) default to 'platform default'; that's why with the Files API it's the one place where you don't have to specify charset.
NB2: With 'new' I mean '10 years old'. Really now. It's fine, surely, even if this is for a course, at this point.
Upvotes: 2
Reputation: 40057
Write the method below to get the key from each string. Then use the following comparator as the argument to the sort method. For this to work the file will need to be read into a List<String>
Comparator<String> comp = (a,b)->getKey(a).compareTo(getKey(b));
public static String getKey(String a) {
int start = a.indexOf("|") + 1;
int end = a.indexOf("|", start);
return a.substring(start, end);
}
Upvotes: 1