Java заменяет все, заменяя одно из каждых двух вхождений - PullRequest
0 голосов
/ 27 июня 2018

У меня странное поведение по действительно простой проблеме.

У меня есть строка с большим количеством нулевых строк:

"а, Ь; с; нуль; нуль; нуль; нуль; нуль; нуль; нуль; нуль; нуль; нуль"

которые я удаляю, используя этот метод:

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;
}

Он работал нормально, пока моя строка не стала больше, и я не увидел этот странный вывод

"а, б, с нулевым ;; ;; ;; нуль-нуль-нуль-;; ;;"

Он удаляет только одно вхождение из двух.

Мне кажется, я понимаю, что во время одной замены программа пропускает одну ";" тогда второе нуль не распознается моим регулярным выражением "; ноль;". Но я не понимаю, почему это происходит?

Ответы [ 3 ]

0 голосов
/ 27 июня 2018

После замены одного экземпляра ";null;" на ";;" обе точки с запятой уже обработаны, поэтому вторая ; не может рассматриваться как начало другой замены для следующего вхождения ";null;". Шаблон не может быть снова сопоставлен до тех пор, пока не будет передан еще один «ноль», чтобы достичь следующей точки с запятой.

То, что вы можете использовать, - это шаблон, который не пытается сопоставить точки с запятой, но он должен проверить, есть ли они там. Вы можете использовать положительный взгляд назад и положительный взгляд вперед (найдите "lookahead" и "lookbehind" на связанной странице). Здесь положительный означает, что он проверяет, что шаблон lookbehind / lookahead существует, но не соответствует ему.

Позитивный вид сзади имеет формат (?<=X), где X - это шаблон, чтобы посмотреть за основным шаблоном, чтобы увидеть, существует ли он. Кроме того, положительный прогноз имеет формат (?=X), где X - это шаблон для просмотра перед основным шаблоном, чтобы увидеть, существует ли он.

Здесь мы ищем начало строки ^ или точку с запятой перед совпадением и конец строки $ или точку с запятой после совпадения. Затем мы просто заменяем фактическое совпадение "null" пустой строкой.

s = s.replaceAll("(?<=^|;)null(?=$|;)", "");
0 голосов
/ 27 июня 2018

Очень простое решение, используйте его вместо приведенного выше большого кода

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

Пример

 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));
}

выход

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;

Обновление , чтобы избежать таких слов, которые содержат ноль, альтернатива здесь

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();
}
0 голосов
/ 27 июня 2018

Вы можете использовать поток, разделив строку

return Stream.of(s.split(";", -1))
             .map(w -> "null".equals(w) ? "" : w)
             .collect(Collectors.joining(";"));
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...