【问题标题】:In Java 8, whats an elegant way to remove certain duplicate words from a string在 Java 8 中,有什么优雅的方法可以从字符串中删除某些重复的单词
【发布时间】:2018-02-09 09:49:30
【问题描述】:

Java 8 中有什么优雅的方法可以从字符串中删除某些特定的重复单词,例如:

带有不重复单词的列表:[cat, mat]

给定一个字符串:“一只猫坐在垫子上,戴着一顶帽子坐在垫子上,戴着一顶帽子”

结果应该是:“一只猫坐在垫子上,戴着帽子 A 坐在垫子上,戴着帽子”

注意:这是我们要保留的第一个匹配项。

【问题讨论】:

标签: java regex string java-8


【解决方案1】:

你可以这样做:

String input = "A cat sat on a mat and wore a hat A cat sat on a mat and wore a hat";

Set<String> toFilter = Set.of("cat", "mat"); // Java 9's set.of, for brievety.
Set<String> seen = new HashSet<>();

String result = Arrays.stream(input.split(" "))
        .filter(s -> !toFilter.contains(s) || seen.add(s))
        .collect(Collectors.joining(" "));

System.out.println(result); // A cat sat on a mat and wore a hat A sat on a and wore a hat

这利用了 seen.add 将在单词已经在集合中返回 false 的事实。


作为对部分cmet的回应,担心单词的顺序没有被保留:

Arrays.stream 的文档没有明确说明返回的流是有序的,但确实提到:

返回一个以指定数组为源的顺序流。

一个数组有一个定义的顺序,即它是有序的,所以我会说它是安全的,因为返回的流也是有序的。

获得有序流的另一种方法是使用Arrays.spliterator 并自己将结果包装在流中(因为拆分器将通过documentation 报告ORDERED):

StreamSupport.stream(Arrays.spliterator(input.split(" ")), false)

但目前,Arrays.stream 也在这样做。


否则,总会有for循环回退:

String[] tokens = input.split(" ");
StringJoiner joiner = new StringJoiner(" ");
for(String s : tokens) {
    if(!toFilter.contains(s) || seen.add(s)) {
        joiner.add(s);
    }
}

String result = joiner.toString();

【讨论】:

  • 但这并不能确保过滤后的订单对象
  • @pvpkiran @tobias_k Afaik 默认情况下,从列表或数组创建的流始终是有序的。如果您检查底层拆分器的特征,它有 ORDERED 那里。但是,当您平行时,这就会分崩离析。
【解决方案2】:

更新了Here 一个使用正向前瞻的示例,删除的词是第一个出现的词

\b(cat|mat)\b(?=.*\b\1\b)

在java中

String input = "A cat sat on a mat and wore a hat A cat sat on a mat and wore a hat";
input = input.replaceAll("\\b(cat|mat)\\b(?=.*\\b\\1\\b)", "");
System.out.println( input );

【讨论】:

  • 只有一个正则表达式的正确答案需要使用不存在的可变大小匹配来查找
  • 您也应该在单词中包含一个空格,否则会留下两个空格(即单词之前和之后的一个)。
  • 现在它会删除第一次出现而不是最后一次出现
  • @anubhava,不仅是第一个,而且除了最后一个,但我问 OP 是否需要,否则字符串应该颠倒
【解决方案3】:

比其他更基本的解决方案;

String input = "A cat sat on a mat and wore a hat A cat sat on a mat and wore a hat";
String[] list = {"cat", "mat"};
    for(String word : list){
        int index = input.indexOf(word) + word.length();
        input = input.substring(0, index) + input.substring(index).replace(word, "");
    }

或者通过使用String.split() 上的“限制”参数,您可以将上面的循环替换为以下内容;

    for(String word : list){
        String[] split = input.split(word, 2);
        input = split[0] + word + split[1].replace(word, "");
    }

这两个都输出A cat sat on a mat and wore a hat A sat on a and wore a hat,但如果您想删除双倍空格,您可以在返回值之前轻松调用input.replaceAll(" {2,}", " "); 以删除任何额外的空格。

【讨论】:

    猜你喜欢
    • 2012-10-31
    • 2022-01-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-14
    相关资源
    最近更新 更多