Java中最佳的字符串查找和替换方法是什么?

32

我正在寻找在Java中进行字符串查找和替换的最佳方法。

这是一个句子:“我的名字是米兰,人们知道我是米兰瓦希奇。”

我想用"Milan Vasic"替换字符串"Milan",但是如果已经有“Milan Vasic”,就不应该替换。

搜索/替换后结果应为:“我的名字是 Milan Vasic,人们知道我是 Milan Vasic。”

我尝试使用indexOf()和Pattern / Matcher组合,但是我的结果都不够简洁优雅。是否有其他更优雅的解决方案?

干杯!


1
在这种情况下,米兰·班迪奇怎么办?我们把米兰·瓦西奇和米兰·班迪奇放在同一个句子中,那么系统会忽略第一个米兰,第二个将是米兰·瓦西奇·班迪奇? :) - ante.sabo
嘿嘿嘿...我在这个例子中使用了我的名字 :) - vaske
7个回答

48

好的,你可以使用正则表达式来查找那些后面不跟着"Vasic"的情况下出现了"Milan"的案例:

Milan(?! Vasic)

并将其替换为全名:

String.replaceAll("Milan(?! Vasic)", "Milan Vasic")

(?!...)部分是负向预查,确保匹配的内容后面没有括号内的内容。它不会在匹配本身中消耗任何字符。

另外,你也可以简单地在名字后面插入(实际上是替换零宽度匹配),除非它已经后跟了姓氏。这看起来类似,但同时使用了正向回顾

(?<=Milan)(?! Vasic)

您可以通过仅使用" Vasic"(请注意字符串开头的空格)来替换此内容:

String.replaceAll("(?<=Milan)(?! Vasic)", " Vasic")

你可以在这里尝试这些东西,例如here

1
使用java.lang.String.replaceAll(String, String)函数 - helios
谢谢,我还没有查过 :) - Joey
嗯,可能不够优雅,但如果你知道正则表达式,阅读起来并不太难。 - Joey
准确地说,我正在学习正则表达式 :) 例如,如果我有“Vasic”并想用前导词替换为“Milan Vasic”,那么反之亦然的解决方案是什么? - vaske
你可以把正向预查改为肯定预查:(?=Vasic),把后行断言改为负向断言:(?<!Milan ) - Joey

25

另外一个选项:

"My name is Milan, people know me as Milan Vasic"
    .replaceAll("Milan Vasic|Milan", "Milan Vasic"))

谢谢,这很有用,也是第一反应! - vaske
1
它不够优雅。它进行了无用的替换。 - ceving

10

有一种可能性,可以在展开所有内容之前缩短较长的形式:

string.replaceAll("Milan Vasic", "Milan").replaceAll("Milan", "Milan Vasic")

另一种方法,将 Vasic 视为可选项:

string.replaceAll("Milan( Vasic)?", "Milan Vasic")

其他人已经描述了基于前瞻选择的解决方案。


不错...但是正则表达式已经让你指定非捕获组了:(?! Milan) - helios
这是一个负向先行断言。非捕获组应该是 (?:...) - Joey

5

当你不想使用正则表达式(也许你应该)时,你可以先将所有的“Milan Vasic”字符串替换为“Milan”。

然后再将所有的“Milan”字符串替换为“Milan Vasic”。


4

试试这个:

public static void main(String[] args) {
    String str = "My name is Milan, people know me as Milan Vasic.";

    Pattern p = Pattern.compile("(Milan)(?! Vasic)");
    Matcher m = p.matcher(str);

    StringBuffer sb = new StringBuffer();

    while(m.find()) {
        m.appendReplacement(sb, "Milan Vasic");
    }

    m.appendTail(sb);
    System.out.println(sb);
}

这是一个很好的例子,其中替换可以在运行时计算。 - Ken Williams

4

只需包含Apache Commons Lang JAR文件,然后使用org.apache.commons.lang.StringUtils类。您会注意到有许多用于安全高效替换字符串的方法。

您可以在之前链接的网站上查看StringUtils API。

“不要重复造轮子”


@ArtOfWarfare Maven和Gradle都很好用,而且与大多数语言不同的是,你不需要构建依赖项,只需拉取它们。因此,这根本不是一个好理由。可能还有更好的依赖管理系统,但PIP不是其中之一(相关xkcd:https://xkcd.com/1987/)。 - drrob
@ArtOfWarfare 我也有多年使用Maven的经验,我不会选择自己编写代码只是因为需要添加几行XML。这就是我的观点。 - drrob
@ArtOfWarfare同意使用正则表达式,这个答案迫切需要一个代码示例,另外Java String可能需要更多的实用方法,但是请为了所有人的利益尽量减少关于Java整体的批评,这会分散寻求答案的人们的注意力,而且在我看来也不合适。 - drrob
1
@drrob - 是的。没必要谈论这个。与问题无关。我删除了之前的评论。只留下这一个:我会给这个答案点踩,因为Java已经内置了完全可用的正则表达式函数。没有必要涉及第三方库。这个答案也没有说明为什么或如何使用那些第三方库。 - ArtOfWarfare

2

您也可以使用模式匹配器,它将一次性替换所有匹配项。

Pattern keyPattern = Pattern.compile(key); Matcher matcher = keyPattern.matcher(str); String nerSrting = matcher.replaceAll(value);


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