Java 使用元字符正则表达式模式执行多个字符串替换
我正在尝试使用Java的模式和匹配器执行多个字符串替换,其中正则表达式模式可能包括元字符,例如.\b等。。例如,对于输入字符串fit i am,我希望应用替换:Java 使用元字符正则表达式模式执行多个字符串替换,java,regex,Java,Regex,我正在尝试使用Java的模式和匹配器执行多个字符串替换,其中正则表达式模式可能包括元字符,例如.\b等。。例如,对于输入字符串fit i am,我希望应用替换: \bi\b --> EYE i --> I 然后,我从两个问题中遵循编码模式。在这两种情况下,它们都创建了一个或“ed”搜索模式,例如foo | bar和模式、替换的映射,在matcher.find循环中,它们查找并应用替换 我遇到的问题是matcher.group函数不包含有关匹配元字符的信息,因此我无法区分I和
\bi\b --> EYE
i --> I
然后,我从两个问题中遵循编码模式。在这两种情况下,它们都创建了一个或“ed”搜索模式,例如foo | bar和模式、替换的映射,在matcher.find循环中,它们查找并应用替换
我遇到的问题是matcher.group函数不包含有关匹配元字符的信息,因此我无法区分I和\bi\b。请参阅下面的代码。我能做些什么来解决这个问题
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.*;
public class ReplacementExample
{
public static void main(String argv[])
{
Map<String, String> replacements = new HashMap<String, String>();
replacements.put("\\bi\\b", "EYE");
replacements.put("i", "I");
String input = "fit i am";
String result = doit(input, replacements);
System.out.printf("%s\n", result);
}
public static String doit(String input, Map<String, String> replacements)
{
String patternString = join(replacements.keySet(), "|");
Pattern pattern = Pattern.compile(patternString);
Matcher matcher = pattern.matcher(input);
StringBuffer resultStringBuffer = new StringBuffer();
while (matcher.find())
{
System.out.printf("match found: %s at start: %d, end: %d\n",
matcher.group(), matcher.start(), matcher.end());
String matchedPattern = matcher.group();
String replaceWith = replacements.get(matchedPattern);
// Do the replacement here.
matcher.appendReplacement(resultStringBuffer, replaceWith);
}
matcher.appendTail(resultStringBuffer);
return resultStringBuffer.toString();
}
private static String join(Set<String> set, String delimiter)
{
StringBuilder sb = new StringBuilder();
int numElements = set.size();
int i = 0;
for (String s : set)
{
sb.append(Pattern.quote(s));
if (i++ < numElements-1) { sb.append(delimiter); }
}
return sb.toString();
}
}
理想情况下,它应该是fIt EYE am。您错误地键入了一个正则表达式:
replacements.put("\\bi\\", "EYE"); //Should be \\bi\\b
replacements.put("i", "I");
您可能还希望使您的正则表达式具有唯一性。map.getKeySet不能保证顺序,因此它可能只是在检查\\bi\\b之前用i替换i。您可以使用捕获组,而不会偏离现有设计太远。因此,不使用匹配的模式作为键,而是根据列表中的顺序进行查找 您需要更改join方法,以便在每个模式周围放置parantises,如下所示:
private static String join(Set<String> set, String delimiter) {
StringBuilder sb = new StringBuilder();
sb.append("(");
int numElements = set.size();
int i = 0;
for (String s : set) {
sb.append(s);
if (i++ < numElements - 1) {
sb.append(")");
sb.append(delimiter);
sb.append("("); }
}
sb.append(")");
return sb.toString();
}
作为补充说明,在原始代码列表中使用Pattern.quote可能会导致在存在这些元字符的地方匹配失败
完成此操作后,您现在需要确定哪个捕获组负责匹配。为简单起见,我将假设所有匹配模式本身都不包含捕获组,在这种情况下,类似这样的内容将在matcher while循环中起作用:
int index = -1;
for (int j=1;j<=replacements.size();j++){
if (matcher.group(j) != null) {
index = j;
break;
}
}
if (index >= 0) {
System.out.printf("Match on index %d = %s %d %d\n", index, matcher.group(index), matcher.start(index), matcher.end(index));
}
接下来,我们希望使用生成的索引值直接索引回替换中。原始代码使用了HashMap,这不适合于此;您必须重构它,以某种形式使用一对列表,一个包含匹配模式列表,另一个包含相应的替换字符串列表。我不会在这里这样做,但我希望这能提供足够的细节来创建一个有效的解决方案 我纠正了那个错误。还是不行。matcher.group同时返回i,因此我无法区分这两种模式。哦,是的,matcher.group将返回它匹配的内容,而不使用任何元字符…性能是否足以成为一个问题,以至于您无法循环替换?替换可能会相互重叠。我提供的第二个链接StackOverflow问题解决了当替换文本与搜索文本重叠时在Java中替换多个子字符串的问题,因此我使用了它的解决方案。用$替换\\wi\\w,然后用EYE替换\\bi\\b,然后用I替换$
int index = -1;
for (int j=1;j<=replacements.size();j++){
if (matcher.group(j) != null) {
index = j;
break;
}
}
if (index >= 0) {
System.out.printf("Match on index %d = %s %d %d\n", index, matcher.group(index), matcher.start(index), matcher.end(index));
}