Java equivalent to PHP's preg_replace_callback
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.
preg_replace_callback just take 5 parameter?
From the PHP manual:
Version 7.4.0 The flags parameter was added.
Upgrade your php version.
Ideally, you shouldn't be using a preg_
function to modify a valid html document. You should use a legitimate dom parser.
Regular expression to remove -
You can use this regex:
(?<=<TN>.*?)\-(?=.*?</TN>)
For Java:
your_string= your_string.replaceAll("(?sim)(?<=<TN>.*?)\\-(?=.*?</TN>)", "");
Java Regex Replace with Capturing Group
The definitive solution to this problem was posted by Elliott Hughes on his blog a couple years ago. Elliott keeps introducing pointless dependencies to other classes in the online version, so I'll post a stand-alone version here (the dependencies are only in the tests in the main()
method).
import java.util.regex.*;
/**
* A Rewriter does a global substitution in the strings passed to its
* 'rewrite' method. It uses the pattern supplied to its constructor, and is
* like 'String.replaceAll' except for the fact that its replacement strings
* are generated by invoking a method you write, rather than from another
* string. This class is supposed to be equivalent to Ruby's 'gsub' when
* given a block. This is the nicest syntax I've managed to come up with in
* Java so far. It's not too bad, and might actually be preferable if you
* want to do the same rewriting to a number of strings in the same method
* or class. See the example 'main' for a sample of how to use this class.
*
* @author Elliott Hughes
*/
public abstract class Rewriter
{
private Pattern pattern;
private Matcher matcher;
/**
* Constructs a rewriter using the given regular expression; the syntax is
* the same as for 'Pattern.compile'.
*/
public Rewriter(String regex)
{
this.pattern = Pattern.compile(regex);
}
/**
* Returns the input subsequence captured by the given group during the
* previous match operation.
*/
public String group(int i)
{
return matcher.group(i);
}
/**
* Overridden to compute a replacement for each match. Use the method
* 'group' to access the captured groups.
*/
public abstract String replacement();
/**
* Returns the result of rewriting 'original' by invoking the method
* 'replacement' for each match of the regular expression supplied to the
* constructor.
*/
public String rewrite(CharSequence original)
{
this.matcher = pattern.matcher(original);
StringBuffer result = new StringBuffer(original.length());
while (matcher.find())
{
matcher.appendReplacement(result, "");
result.append(replacement());
}
matcher.appendTail(result);
return result.toString();
}
public static void main(String... args) throws Exception
{
String str = "12 54 1 65";
// anonymous subclass
Rewriter tripler = new Rewriter("(\\d{1,2})")
{
public String replacement()
{
int intValue = Integer.valueOf(group(1));
return String.valueOf(intValue * 3);
}
};
System.out.println(tripler.rewrite(str));
// inline subclass
System.out.println(new Rewriter("(\\d{1,2})")
{
public String replacement()
{
int intValue = Integer.valueOf(group(1));
return String.valueOf(intValue * 3);
}
}.rewrite(str));
}
}
Get what was removed by String.replaceAll()
You can use a Matcher
with the append-and-replace procedure:
String regex = "\\d*";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(input);
StringBuffer sb = new StringBuffer();
StringBuffer replaced = new StringBuffer();
while(matcher.find()) {
replaced.append(matcher.group());
matcher.appendReplacement(sb, "");
}
matcher.appendTail(sb);
System.out.println(sb.toString()); // prints the replacement result
System.out.println(replaced.toString()); // prints what was replaced
Java: replace a set of characters with other different characters
It would be easier to first create some kind of mapping between replaced character and its replacement. I mean something like
Map<String, String> map = new HashMap<>();
map.put("a", "c");
map.put("b", "d");
then you can use appendReplacement
and appendTail
from Matcher class to replace matched character. Deciding on how to get replaced character can be done like map.get(matchedCharacter)
.
Simple Demo
Map<String, String> map = new HashMap<>();
map.put("a", "c");
map.put("b", "d");
String demo = "abcdef";
Pattern p = Pattern.compile("[ab]");
Matcher m = p.matcher(demo);
StringBuffer sb = new StringBuffer();
while (m.find()){
m.appendReplacement(sb, map.get(m.group()));
}
m.appendTail(sb);
String replaced = sb.toString();
System.out.println(replaced);
Output: cdcdef
UPDATE for Java 9 and above
In below template we usually change only one thing, decision about what to use as replacement of founded match.
StringBuffer sb = new StringBuffer();
while (m.find()){
m.appendReplacement(sb, /* decision about replacement*/ );
// ^^^^^^^^^^^^^^^^^^^^^^^^^^
}
m.appendTail(sb);
String replaced = sb.toString();
So since rest of that logic is repeated, this template was wrapped as String replaceAll(Function<MatchResult,String> replacer)
which require from us to provide logic of obtaining replacement for founded match. So above code can be reduced to:
Map<String, String> map = new HashMap<>();
map.put("a", "c");
map.put("b", "d");
String demo = "abcdef";
Pattern p = Pattern.compile("[ab]");
Matcher m = p.matcher(demo);
String replaced = m.replaceAll(match -> map.get(match.group()));
System.out.println(replaced);
Is it possible to switch between + and - using regex in Java?
You can use this trick :
String equation = "<Your equation>"
equation = equation.replaceAll("+","$$$");
equation = equation.replaceAll("-","+");
equation = equation.replaceAll("$$$","-");
Assuming $$$ is not in your equation.
Related Topics
How to Set a Custom Font For Entire of Application
Firebaselistadapter Not Pushing Individual Items For Chat App - Firebase-Ui 3.1
Android 6.0 Multiple Permissions
How to Pass a Bitmap Object from One Activity to Another
Inner Class Can Access But Not Update Values - Asynctask
Launching Google Maps Directions Via an Intent on Android
How to Add a Timestamp in Firestore With Android
How to Redirect Multiple Types of Users to Their Respective Activities
Android Update 17 Seems Incompatible With External Jars
Custom Listview Adapter Getview Method Being Called Multiple Times, and in No Coherent Order
How to Parse Json Array (Not Json Object) in Android
The Asynctask API Is Deprecated in Android 11. What Are the Alternatives
How to Read a Text File in Android
Java.Text.Parseexception: Unparseable Date: Java.Text.Dateformat.Parse(Dateformat.Java:579)
Com.Android.Build.Transform.API.Transformexception
How to Display Data from Firestore in a Recyclerview With Android