我正在尝试使用以下代码来替换整个字符串:
代码:
字符串 a = "你好";
String b = a.replaceAll("(?s).*", "US");
输出:
USUS
问题: 为什么字符串“US”重复两次? 如何使用正则表达式使用 replaceAll 函数替换整个字符串?
为什么我需要这样做: 我需要使用那里给定的值来选择 json 文件中指定的替换模式。在这个模型中,我想给用户(json 配置器)独立性来定义一个模式,这样整个字符串都可以被替换,而我不必编写字符串替换的特殊处理代码。
最佳答案
这是因为 Matcher
类如何处理可能匹配空字符串的模式。 String
的 replaceAll
方法定义为与 Matcher
的 replaceAll
方法相同的工作方式,其工作方式如下这个:
This method first resets this matcher. It then scans the input sequence looking for a match of the pattern. Characters that are not part of the match are appended directly to the result string; the match is replaced in the result by the replacement string. The replacement string may contain references to captured subsequences as in the appendReplacement method.
当匹配器尝试查找模式时,如果源中的子序列是空字符串,则匹配器返回空字符串,然后将当前索引增加 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 中看到它。我想这意味着 future 版本的 JRE 可能会有所不同,尽管这似乎不太可能。
关于java - 使用 Java 的 replaceAll 替换整个字符串,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26240607/