I'm in the process of moving an application from PHP to Java and there is heavy use of regular expressions in the code. I've run across something in PHP that doesn't seem to have a java equivalent:
preg_replace_callback()
For every match in the regex, it calls a function that is passed the match text as a parameter. As an example usage:
$articleText = preg_replace_callback("/\[thumb(\d+)\]/",'thumbReplace', $articleText); # ... function thumbReplace($matches) { global $photos; return "<img src=\"thumbs/" . $photos[$matches[1]] . "\">"; }
What would be the ideal way to do this in Java?
Trying to emulate PHP's callback feature seems an awful lot of work when you could just use appendReplacement() and appendTail() in a loop:
StringBuffer resultString = new StringBuffer(); Pattern regex = Pattern.compile("regex"); Matcher regexMatcher = regex.matcher(subjectString); while (regexMatcher.find()) { // You can vary the replacement text for each match on-the-fly regexMatcher.appendReplacement(resultString, "replacement"); } regexMatcher.appendTail(resultString);
IMPORTANT: As pointed out by Kip in the comments, this class has an infinite loop bug if the matching regex matches on the replacement string. I'll leave it as an exercise to readers to fix it, if necessary.
I don't know of anything similar that's built into Java. You could roll your own without too much difficulty, using the Matcher class:
import java.util.regex.*; public class CallbackMatcher { public static interface Callback { public String foundMatch(MatchResult matchResult); } private final Pattern pattern; public CallbackMatcher(String regex) { this.pattern = Pattern.compile(regex); } public String replaceMatches(String string, Callback callback) { final Matcher matcher = this.pattern.matcher(string); while(matcher.find()) { final MatchResult matchResult = matcher.toMatchResult(); final String replacement = callback.foundMatch(matchResult); string = string.substring(0, matchResult.start()) + replacement + string.substring(matchResult.end()); matcher.reset(string); } } }
Then call:
final CallbackMatcher.Callback callback = new CallbackMatcher.Callback() { public String foundMatch(MatchResult matchResult) { return "<img src=\"thumbs/" + matchResults.group(1) + "\"/>"; } }; final CallbackMatcher callbackMatcher = new CallbackMatcher("/\[thumb(\d+)\]/"); callbackMatcher.replaceMatches(articleText, callback);
Note that you can get the entire matched string by calling matchResults.group()
or matchResults.group(0)
, so it's not necessary to pass the callback the current string state.
EDIT: Made it look more like the exact functionality of the PHP function.
Here's the original, since the asker liked it:
public class CallbackMatcher { public static interface Callback { public void foundMatch(MatchResult matchResult); } private final Pattern pattern; public CallbackMatcher(String regex) { this.pattern = Pattern.compile(regex); } public String findMatches(String string, Callback callback) { final Matcher matcher = this.pattern.matcher(string); while(matcher.find()) { callback.foundMatch(matcher.toMatchResult()); } } }
For this particular use case, it might be best to simply queue each match in the callback, then afterwards run through them backwards. This will prevent having to remap indexes as the string is modified.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With