Java String.replaceAll() 与反向引用

2022-09-02 19:41:46

有一个Java正则表达式问题:给定一个字符串,如果“*”在字符串的开头或结尾,请保留它,否则将其删除。例如:

  1. * --> *
  2. ** --> **
  3. ******* --> **
  4. *abc**def* --> *abcdef*

答案是:

str.replaceAll("(^\\*)|(\\*$)|\\*", "$1$2");

我在我的机器上尝试了答案,它的工作原理。但我不知道它是如何工作的。

根据我的理解,所有匹配的子字符串都应替换为 。但是,它的工作原理是:$1$2

  1. (^\\*)替换为 、$1
  2. (\\*$)替换为 、$2
  3. \\*替换为空。

有人可以解释它是如何工作的吗?更具体地说,如果表达式之间存在,如何使用反向引用?|String.replaceAll()

提前感谢您。


答案 1

我将尝试解释正则表达式中发生的情况。

str.replaceAll("(^\\*)|(\\*$)|\\*", "$1$2");

$1表示第一组,表示第二组(^\\*)$2(\\*$)

当您调用 时,您实质上是捕获两个组和其他所有内容,但是在替换时,请将捕获的文本替换为在两个组中捕获的任何内容。str.replaceAll

例:*abc**def* --> *abcdef*

正则表达式是以 开头的字符串,它将放入组中,接下来它将继续查找,直到它在组的末尾找到并将其存储在.现在更换时,它将消除除一个存储或*$1*#2*$1$2

有关详细信息,请参阅捕获组


答案 2

您可以在正则表达式中使用查找:

String repl = str.replaceAll("(?<!^)\\*+(?!$)", "");

正则表达式演示

正则表达式分解:

(?<!^)   # If previous position is not line start
\\*+     # match 1 or more *
(?!$)    # If next position is not line end

OP的正则表达式是:

(^\*)|(\*$)|\*

它使用 2 个捕获的组,一个用于开头,另一个用于末尾,并在替换中使用反向引用。这可能在这里工作,但对于更大的字符串,完成速度会慢得多,这在本演示中采取的步骤#中很明显。这是209对48步使用环顾四周。**

OP正则表达式中另一个较小的改进是使用量词

(^\*)|(\*$)|\*+