我正在尝试使用以下代码来替换整个字符串:
代码:
String a = "Hello";
String b = a.replaceAll("(?s).*", "US");
输出:
USUS
问题: 为什么字符串" US"重复了两次? 如何使用replaceAll函数替换整个字符串,使用正则表达式?
为什么我需要这样做: 我需要使用其中给出的值来获取json文件中指定的替换模式。在这个模型中,我想给用户独立(json configurer)来定义一个模式,这样整个字符串就可以被替换,而不需要对字符串替换的特殊处理进行编码。
答案 0 :(得分:3)
这是因为Matcher
类处理可能与空字符串匹配的模式。 replaceAll
String
方法的定义方式与replaceAll
Matcher
方法的工作方式相同,其工作原理如下:
此方法首先重置此匹配器。然后它扫描输入 序列寻找模式的匹配。不是的字符 匹配的一部分直接附加到结果字符串;该 匹配由替换字符串替换为结果。该 替换字符串可能包含对捕获的子序列的引用 在appendReplacement方法中。
当匹配器尝试查找模式时,如果源中的子序列是空字符串,则匹配器返回空字符串,但然后将当前索引加上1,这样它就不会返回空的无限循环字符串。所以这是它在"Hello"
上的运作方式:
1)匹配器查找.*
。由于这是一个贪婪的匹配,匹配尽可能多的字符,它将找到子字符串"Hello"
,并使用它,将其替换为"US"
。然后将当前索引定位在'o'
之后。
2)匹配器再次查找.*
。由于它位于输入的末尾,但允许模式匹配空字符串,因此它匹配空字符串并将其替换为另一个"US"
。但随后它突破了目前的指数,目前该指数处于源头结束时的位置。
3)匹配器再次查找.*
,但由于当前索引超过了源的末尾,因此找不到任何内容。
要了解其运作方式,请尝试使用".*?"
作为模式。现在,匹配器总是使用空字符串,因为?
告诉它使用最短的字符串。每次找到空字符串时,它还会将当前索引增加1。结果:
a.replaceAll("(?s).*?", ".-") //returns
".-H.-e.-l.-l.-o.-"
也就是说,它用".-"
替换每对字符之间的所有空字符串,并保留实际字符。
道德:要非常小心可以匹配空字符串的模式。
更多:在阅读您的评论后,您指出该模式可以由用户输入,我认为您可以将其用作测试,以查看该模式是否可以匹配空字符串:
if ("".matches(inputPattern)) {
// ???
}
我不确定你用它做什么。也许情况总是如此,如果这是真的,您的replaceAll
会在最后添加额外的US
,您可以安全地将其删除。或许你可以告诉他们尝试不同的模式。
PPS。我不确定匹配器的这种行为(即当匹配为空字符串时将当前索引增加1)的位置。我没有在Matcher
javadoc中看到它。我想这意味着JRE的未来版本可能会有不同的表现,尽管这似乎不太可能。
答案 1 :(得分:1)
因为.*
可以匹配空字符串。所以第一个匹配是所有字符串(从开始),第二个是空字符串(从最后一个字符后面的字符串的最后一个位置)
您可以使用+
量词而不是*
来避免此行为。但它不会取代空字符串。