Java 全部替换,每两次替换一次

Java replace all replacing one of every two occurrences

我在一个非常简单的问题上有一个奇怪的行为。

我有一个包含很多空字符串的字符串:

"a;b;c;null;null;null;null;null;null;null;null;null;null"

我用这个方法删除的:

public String replaceAllNull(String s) {
    s = s.replaceAll(";null;", ";;");

    //if first item = null remove it
    if(s.startsWith("null;")) {
        s = s.substring(4,s.length());
    }

    //if last item = null remove it
    if(s.endsWith(";null")) {
        s = s.substring(0,s.length()-4);
    }
    return s;
}

在我的字符串变大并且我看到这个奇怪的输出之前它一直工作正常

"a;b;c;;null;;null;;null;;null;;"

它只会从两次中删除一次。

我想我可以理解在一个替换程序中跳过一个“;”那么我的正则表达式“;null;”无法识别第二个 null。但我不明白为什么会这样?

您可以通过拆分字符串来使用 Stream

return Stream.of(s.split(";", -1))
             .map(w -> "null".equals(w) ? "" : w)
             .collect(Collectors.joining(";"));

";null;"的一个实例被";;"替换后,两个分号都已经被处理了,所以第二个;不能被认为是另一个替换的开始下一次 ";null;" 事件。在另一个 "null" 被向上传递以到达下一个分号之前,无法再次匹配该模式。

您可以使用一种不尝试匹配分号的模式,但它必须检查分号是否存在。您可以使用 a positive lookbehind and a positive lookahead(在链接页面上找到 "lookahead" 和 "lookbehind")。在这里,positive 意味着它验证 lookbehind/lookahead 的模式存在,但不匹配它。

正后视的格式为 (?<=X),其中 X 是在主模式后面查看其是否存在的模式。此外,正向预测的格式为 (?=X),其中 X 是预测主模式是否存在的模式。

在这里,我们查找行首 ^ 或匹配前的分号,以及行尾 $ 或匹配后的分号。然后我们简单地用空字符串替换实际匹配项 "null"

s = s.replaceAll("(?<=^|;)null(?=$|;)", "");

一个很简单的解决方案,用这个代替上面的大代码

public String replaceAllNull(String s) {
    return s.replace("null" , "");
}

Example

 public static void main(String []args){
    String str = "a;r;c;e;null;d;f;e;null;s;null;null;null;null;null;null;null;null;null;null;null;null;null;null;null;null;s;";
    System.out.println(String.format("Before replacing null %s", str));
    str = replaceAllNull(str);
    System.out.println(String.format("After replacing null %s", str));
}

Output

Before replacing null a;r;c;e;null;d;f;e;null;s;null;null;null;null;null;null;null;null;null;null;null;null;null;null;null;null;s;
After replacing null a;r;c;e;;d;f;e;;s;;;;;;;;;;;;;;;;;s;

Update to avoid such words that contains null in it, an alternate is here

public static String replaceAllNull(String s) {
    String[] arr = s.split(";");
    for (int i = 0; i < arr.length; i++) {
        if (arr[i].equalsIgnoreCase("null"))
            arr[i] = "";
    }
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < arr.length; i++) {
        sb.append(arr[i]);
        if (i < arr.length - 1)
            sb.append(";");
    }
    if (s.endsWith(";"))
        sb.append(";");
    return sb.toString();
}