Java正则表达式字符串#替换所有可选项
我一直在尝试设计一种方法,用模式/匹配器实例替换多个String#replaceAll调用,希望它比我当前替换字符串中文本的方法更快,但我不确定该怎么做 下面是我想要操纵的字符串示例:Java正则表达式字符串#替换所有可选项,java,regex,string,pattern-matching,substring,Java,Regex,String,Pattern Matching,Substring,我一直在尝试设计一种方法,用模式/匹配器实例替换多个String#replaceAll调用,希望它比我当前替换字符串中文本的方法更快,但我不确定该怎么做 下面是我想要操纵的字符串示例: @bla@This is a @red@line @bla@of text. 如您所见,有多个@字符,中间有3个字符;这将永远是事实。如果我想替换“@xxx@”(其中xxx可以是0到9之间的任何小写字母或数字)的每个实例,那么最有效的方法是什么?目前,我正在存储一个映射,其中其键是'@xxx@'子字符串,并且这
@bla@This is a @red@line @bla@of text.
如您所见,有多个@字符,中间有3个字符;这将永远是事实。如果我想替换“@xxx@”(其中xxx可以是0到9之间的任何小写字母或数字)的每个实例,那么最有效的方法是什么?目前,我正在存储一个映射,其中其键是'@xxx@'子字符串,并且这些值是我要用以替换该特定子字符串的值;我检查整个字符串是否包含'@xxx@'子字符串,并为每个实例调用replaceAll方法,但我认为这是非常低效的
多谢各位
TL;DR-模式/匹配器用不同的字符串替换字符串的子字符串是否比检查字符串是否包含子字符串并使用字符串#replaceAll更有效?如果是这样的话,我该怎么做呢?这是一个相对简单的例子:
//准备替换地图
Map replacement=newhashmap();
替换。放置(“bla”、“hello”);
替换。放置(“红色”、“世界!”);
//使用与两个@s之间的三个非@s匹配的模式
Pattern p=Pattern.compile(“@([^@]{3}”);
匹配器m=p.Matcher(“@bla@This是一个@red@line @bla@of案文“);
StringBuffer sb=新的StringBuffer();
while(m.find()){
//第1组捕获@s之间的内容
字符串标记=m.group(1);
String repString=replacement.get(标记);
if(repString==null){
System.err.println(“Tag@+Tag+@是意外的。”);
继续;
}
//替换可以有特殊字符,例如\'
//Matcher.quoteReplacement()将正确处理它们:
m、 附录替换(sb,匹配器引用替换(repString));
}
m、 (某人);
字符串结果=sb.toString();
这是另一个类似问题的更动态版本
这里有一个助手方法,用于搜索您想要的任何@关键字@
。它们不必有3个字符长
private static String replace(String input, Map<String, String> replacement) {
StringJoiner regex = new StringJoiner("|", "@(", ")@");
for (String keyword : replacement.keySet())
regex.add(Pattern.quote(keyword));
StringBuffer output = new StringBuffer();
Matcher m = Pattern.compile(regex.toString()).matcher(input);
while (m.find())
m.appendReplacement(output, Matcher.quoteReplacement(replacement.get(m.group(1))));
return m.appendTail(output).toString();
}
“replaceAll”已经是正则表达式;学习使用正则表达式。@Boristespider问题不是如何编写正则表达式,而是如何用依赖于
关键字的值替换多个不同的@keyword@
模式,而不使用多个replaceAll()
调用。诀窍是Matcher
@Andreas谢谢,这是一种非常有趣的方法,只需搜索字符串一次。使用StringBuffer而不是StringBuilder有什么原因吗?另外,如果我有大约50个不同的可能的子字符串可以替换,它不会变得有点冗长吗?我投票重新打开这个问题。我认为复制品非常接近,但它的答案不能很好地匹配大量不同的替代品,如OP的例子。尽管答案肯定可以重复,但我认为直接回答这个问题有好处。@JacobG。它使用StringBuffer
,因为这是appendReplacement()
所需要的(在Java 8中)。我相信Java 9中添加了一个StringBuilder
重载。由于我的字符串在@characters之间只有3个字符,这正是我想要的,谢谢!我真的希望我能接受你的两个答案,因为它们都足够了,但我的子字符串在@符号之间只有3个字符长。不过,我想这肯定会对将来的人有所帮助,谢谢!这很好,尤其是使用模式。引号(关键字)
很容易错过。@dasblinkenlight-DOH!我忘记了更容易错过的Matcher.quoteReplacement()
。固定的.-)@安德烈亚斯,我也错过了那个。谢谢这是一个非常好的回答。我只想补充一点,如果我们可以假设关键字
文本可以有不同的长度,一个可以包含另一个,比如foo
和foobar
,那么我们就不能允许regex生成器创建类似regex的foo | foobar
,因为foo
总是会阻止foobar
被匹配。这可以通过按长度降序排列文字来解决。
private static String replace(String input, Map<String, String> replacement) {
StringJoiner regex = new StringJoiner("|", "@(", ")@");
for (String keyword : replacement.keySet())
regex.add(Pattern.quote(keyword));
StringBuffer output = new StringBuffer();
Matcher m = Pattern.compile(regex.toString()).matcher(input);
while (m.find())
m.appendReplacement(output, Matcher.quoteReplacement(replacement.get(m.group(1))));
return m.appendTail(output).toString();
}
private static String replace(String input, Map<String, String> replacement) {
String regex = replacement.keySet().stream()
.sorted(Comparator.comparingInt(String::length).reversed())
.map(Pattern::quote).collect(Collectors.joining("|", "@(", ")@"));
return Pattern.compile(regex).matcher(input)
.replaceAll(m -> Matcher.quoteReplacement(replacement.get(m.group(1))));
}
Map<String,String> replacement = new HashMap<>();
replacement.put("bla", "hello,");
replacement.put("red", "world!");
replacement.put("Hold", "wait");
replacement.put("Better", "more");
replacement.put("a?b*c", "special regex characters");
replacement.put("foo @ bar", "with spaces and the @ boundary character work");
System.out.println(replace("@bla@This is a @red@line @bla@of text", replacement));
System.out.println(replace("But @Hold@, this can do @Better@!", replacement));
System.out.println(replace("It can even handle @a?b*c@ without dying", replacement));
System.out.println(replace("Keyword @foo @ bar@ too", replacement));