用Java正则表达式替换多个捕获组

7

我有这个需求——对于像下面展示的输入字符串

8This8 is &reallly& a #test# of %repl%acing% %mul%tiple 9matched9 9pairs

我想要去除匹配单词的边界(其中匹配对是8、&或%等字符),结果如下:

This is really a test of repl%acing %mul%tiple matched 9pairs

这个用于成对匹配的字符列表可能会有所变化,例如8、9、%、#等,只有与每种类型开头和结尾相匹配的单词将被剥离这些字符,而嵌入在单词中的相同字符将保持不变。
使用Java,我可以使用模式如“\\b8([^\\s]*)8\\b”和替换为$1,以捕获并替换所有8...8的出现,但是如何为所有类型的成对进行此操作?
我可以提供一个模式,例如“\\b8([^\\s]*)8\\b|\\b9([^\\s]*)9\\b”等,将匹配所有类型的匹配对(*8,9等),但是如何指定“可变”的替换组?
例如,如果匹配是9...9,则替换应为$2。
当然,我可以运行多个这样的程序,每个程序替换特定类型的成对,但我想知道是否有更优雅的方法。
还是有完全不同的方法来解决这个问题吗?
谢谢。
2个回答

4
您可以使用以下正则表达式,然后将匹配的字符替换为组索引2中存在的字符。
(?<!\S)(\S)(\S+)\1(?=\s|$)

或者

(?<!\S)(\S)(\S*)\1(?=\s|$)

Java 的正则表达式可以写成:

(?<!\\S)(\\S)(\\S+)\\1(?=\\s|$)

DEMO

String s1 = "8This8 is &reallly& a #test# of %repl%acing% %mul%tiple 9matched9 9pairs";
System.out.println(s1.replaceAll("(?<!\\S)(\\S)(\\S+)\\1(?=\\s|$)", "$2"));

输出:

This is reallly a test of repl%acing %mul%tiple matched 9pairs

Explanation:
  • (?<!\\S) 表示负向后行断言,匹配的字符前面不能是非空格字符。
  • (\\S) 捕获第一个非空格字符并将其存储到第一组中。
  • (\\S+) 捕获一个或多个非空格字符。
  • \\1 引用第一个捕获组中的字符。
  • (?=\\s|$) 匹配后面紧跟着空格或者行尾锚点的文本。
  • 该正则表达式确保字符串的第一个字符和最后一个字符相同。如果是,则用第二组中存在的字符替换整个匹配。

对于这种特定情况,您可以修改上述正则表达式如下:

String s1 = "8This8 is &reallly& a #test# of %repl%acing% %mul%tiple 9matched9 9pairs";
System.out.println(s1.replaceAll("(?<!\\S)([89&#%])(\\S+)\\1(?=\\s|$)", "$2"));

DEMO


1
谢谢。像你和另一个人建议的那样,使用反向引用和捕获组到2似乎已经解决了问题。我正在使用以下正则表达式:(?<!\S)(8|9|&|#|%)(\S+)\1(?=\s|$),其中第一个捕获组包含可以成为配对模式一部分的所有字符列表。 - ssen
@ssen,你说得对。更简化的正则表达式是 (?<!\S)([89&#%])(\S+)\1(?=\s|$)。https://regex101.com/r/qB0jV1/19 - Avinash Raj

1
(?<![a-zA-Z])[8&#%9](?=[a-zA-Z])([^\s]*?)(?<=[a-zA-Z])[8&#%9](?![a-zA-Z])

尝试使用此方法。将其替换为$1\1。请参见演示。

https://regex101.com/r/qB0jV1/15

(?<![a-zA-Z])[^a-zA-Z](?=[a-zA-Z])([^\s]*?)(?<=[a-zA-Z])[^a-zA-Z](?![a-zA-Z])

如果您有多个定界符,请使用此选项。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接