Issue
Problem
I want to reduce a stream of MatchResults
to a String
. Is there a method in the standard-library for this or do I have to write a custom Collector
?
Currently, my method looks like this:
public static String pointUnderlineRunnables(String line, String regex) {
List<MatchResult> matches = Pattern.compile(regex).matcher(line).results() // Finds matches
.filter(mRes -> ProgramHelper.isRunnableCode(mRes.start(), line)) // Filters out "quoted strings" and comments
.toList();
String underline = "";
for (MatchResult m : matches)
underline += " ".repeat(m.start() - underline.length()) + "^".repeat(m.end() - m.start());
return line.strip() + "\n" + underline;
}
But with the proviced mapping methods I cannot write this:
public static String pointUnderlineRunnables(String line, String regex) {
return line.strip() + "\n" + Pattern.compile(regex).matcher(line).results() //
.filter(mRes -> ProgramHelper.isRunnableCode(mRes.start(), line)) //
.reduce("", (subtotal, elem) //
-> subtotal + " ".repeat(elem.start() - subtotal.length()) + "^".repeat(elem.end() - elem.start());
}
...because both the subtotal and the element have to share the same type. Is there another method that I just don't know, that does this?
Edit: The method underlines all occurences of the regex in the line without a few filtered exceptions.
Sample
Input:
- line: "I love food, food is cool!"
- regex: "food"
Output:
I love food, food is cool!
^^^^ ^^^^
Solution
You can use this version of reduce :
public static String pointUnderlineRunnables(String line, String regex) {
String underline = Pattern.compile(regex)
.matcher(line)
.results()
.filter(mRes -> ProgramHelper.isRunnableCode(mRes.start(), line))
.reduce("",
(str,mr) -> str.concat(" ".repeat(mr.start() - str.length()) + "^".repeat(mr.end() - mr.start())),
String::concat);
return line.strip() + "\n" + underline;
}
To make it somehow readable you could extract the BiFunction:
public static String pointUnderlineRunnables(String line, String regex) {
BiFunction<String,MatchResult,String> func = (str,mr) ->
str.concat(" ".repeat(mr.start() - str.length()) + "^".repeat(mr.end() - mr.start()));
String underline = Pattern.compile(regex)
.matcher(line)
.results()
.filter(mRes -> ProgramHelper.isRunnableCode(mRes.start(), line))
.reduce("",func::apply, String::concat);
return line.strip() + "\n" + underline;
}
Answered By - Eritrean
Answer Checked By - Cary Denson (JavaFixing Admin)