【问题标题】:how to replace multiple matched Regex如何替换多个匹配的正则表达式
【发布时间】:2016-03-14 20:14:17
【问题描述】:

我有一组正则表达式替换,需要应用于一组字符串,

例如:

  1. 所有带有单个空格的多个空格("\s{2,}" --> " ")
  2. 全部。后跟一个带有 .后跟空格,后跟字符 (\.([a-zA-Z]-->". $1")

所以我会有这样的东西:

String s="hello     .how are you?";
s=s.replaceAll("\\s{2,}"," ");
s=s.replaceAll("\\.([a-zA-Z])",". $1");
....

它有效,但是想象一下我正在尝试在一个长字符串上替换 100 多个这样的表达式。不用说这有多慢。

所以我的问题是,是否有一种更有效的方法可以使用单个 replaceAll(或类似的东西,例如 Pattern/Matcher)来概括这些替换

我已关注Java Replacing multiple different...

但问题是我的正则表达式不是simple Strings

【问题讨论】:

  • 你可以使用一个大的正则表达式和Matcher.appendReplacement。但是,您必须非常小心您的正则表达式 - 因为它可能会变得有些混乱,并且可能会遭受灾难性的回溯。
  • @BoristheSpider 如果我使用它,那么我就会知道使用了哪个正则表达式。
  • 不,只需使用捕获组并检查其中有数据。
  • @BoristheSpider 假设我匹配 .A 我怎么知道这是否匹配使用 \\.([a-zA-Z])
  • 如果你有一个模式,例如(A)|(B),那么你知道,当你得到一个匹配项时,第 1 组或第 2 组将被填充 - 另一个将为空(this bug 除外) .您可以使用它来确定替换。

标签: java regex string


【解决方案1】:

你有这 2 个replaceAll 电话:

s = s.replaceAll("\\s{2,}"," ");
s = s.replaceAll("\\.([a-zA-Z])",". $1");

您可以像这样将它们组合成一个replaceAll

s = s.replaceAll("\\s{2,}|(\\.)(?=[a-zA-Z])", "$1 ");

RegEx Demo

【讨论】:

  • 这是一个很好的观察伙伴,但不幸的是还有许多其他规则无法适应这种技术
  • 我根据您有问题的代码发布了答案。如果您显示更多代码,那么我可以更好地判断可以做些什么来优化它。
  • thx 伙计,100 多条规则,添加它们显然没有意义,还有这个([a-zA-Z])\\-,([a-zA-Z]) --> $1-$2
  • @nafas 这是一个好的解决方案的基础,即使你的表达式很“复杂”。如果您可以根据常见的替换表达式对所有正则表达式进行分组,然后使用正则表达式交替将调用链接到replaceAll()(如本例所示),它将尽可能高效。例如s = s.replaceAll("\\s{2,}|(\\.)(?=[a-zA-Z])", "$1 ").replaceAll("foo|bar|baz", "qux").replaceAll...;
  • @Bohemian 我同意,老实说,当 anubhava 设法将它们结合起来时,我感到很惊讶。这样我可以减少我正在使用的正则表达式的数量,但仍然必须有很多 repalceAll 等等......,我想没有希望单个班轮或更复杂的东西。
【解决方案2】:

查看Replace multiple substrings at Once 并修改它。

使用Map<Integer, Function<Matcher, String>>

  • 将数字分组为整数键
  • 作为值的 Lambdas

修改循环以检查匹配的组。然后使用该组号来获取替换 lambda。

伪代码

Map<Integer, Function<Matcher, String>> replacements = new HashMap<>() {{
    put(1, matcher -> "");
    put(2, matcher -> " " + matcher.group(2));
}};

String input = "lorem substr1 ipsum substr2 dolor substr3 amet";

// create the pattern joining the keys with '|'. Need to add groups for referencing later
String regexp = "(\\s{2,})|(\\.(?:[a-zA-Z]))";

StringBuffer sb = new StringBuffer();
Pattern p = Pattern.compile(regexp);
Matcher m = p.matcher(input);

while (m.find()) {
    //TODO change to find which groupNum matched
    m.appendReplacement(sb, replacements.get(m.group(groupNum)));
}
m.appendTail(sb);


System.out.println(sb.toString());   // lorem repl1 ipsum repl2 dolor repl3 amet

【讨论】:

    猜你喜欢
    • 2012-09-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-16
    • 1970-01-01
    • 1970-01-01
    • 2013-12-06
    • 2021-04-10
    相关资源
    最近更新 更多