Esapi и использование replaceAll для пустых строк

Я видел упоминание об использовании String.replaceAll("",""); как средства удаления «пустых» или «непечатаемых символов» из строки в Java. Это неверно, как покажет ответ.

value = value.replaceAll("", "");


person avgvstvs    schedule 10.05.2014    source источник
comment
Чего вы пытаетесь достичь?   -  person Pedro Lobito    schedule 11.05.2014
comment
Утверждалось, что рассматриваемая строка кода была стандартной практикой для esapi. Поскольку я не согласен с тем, что это стандарт, моя цель состояла в том, чтобы продемонстрировать, что если это практика, которую кто-то использует, то это неправильная практика: она ничего не делает. ИЛИ, если это ЯВЛЯЕТСЯ правильной практикой, бросить вызов моему тестовому примеру и продемонстрировать действительный тестовый пример, подтверждающий правильность практики.   -  person avgvstvs    schedule 11.05.2014


Ответы (1)


Используя Junit, я тестирую каждый символ Unicode от до ￿.

@Test
public void testReplaceBlanks(){
char input = 0;
char escape = '\u0000';

for(char i = 0; i <= 65535; ++i){
    input = (char) (escape + i);
    System.out.print(input);
    System.out.print(" ");
    if( i % 80 == 0){
        System.out.println();
    }

    String test = new String(Character.toString(input));
    assertTrue(!"".equals(test.replaceAll("", "")));

    if(i == 65535)
        break;
}
}

Я не нахожу ни одного случая, когда эта строка кода делает что-то полезное.

Поскольку я еще пару раз замечал эту проблему в Интернете, вот более надежный тестовый пример:

Основная проблема здесь, эта строка кода является NO-OP.

значение = значение.replaceAll («», «»);

Рассмотрим следующий тестовый пример:

  public static void println(String s) {
    System.out.println(s);
  }

  @Test
  public void testNullStripWithEmptyString() {
    String input = "foo" + '\0';
    String input2 = "foo";
    println(input);
    println("input:");
    printBytes(input.getBytes());
    println("input2:");
    printBytes(input2.getBytes());
    String testValue = input.replaceAll("", "");
    println("testValue:");
    printBytes(testValue.getBytes());
    String testvalue2 = input2.replaceAll("","");
    println("testvalue2");
    printBytes(testvalue2.getBytes());
    assertFalse(input.equals(input2));
    assertFalse(testValue.equals(testvalue2));
  }

Этот тестовый пример демонстрирует, во-первых, что в байтовых представлениях двух входных строк нулевой байт появляется в первой, но не во второй. Затем мы переходим к вызову *.replaceAll("",""); и сохраните значения в двух новых переменных, testValue и testvalue2.

Затем это приводит к первому утверждению, которое утверждает, что два значения не должны быть равны, вызывая обычный метод String equals. Это тривиально верно, потому что у нас ДЕЙСТВИТЕЛЬНО есть непечатаемый нулевой байт, добавленный к строке. Однако гвоздь в крышку гроба заключается в демонстрации того, что это условие остается в силе после вызова *.replaceAll("",""); в двух строках testValue.

Единственный способ предотвратить непечатаемые или пустые байты — реализовать следующий тестовый пример:

  @Test 
  public void testNullStripWithNullUnicodeEscape(){
    String input = "foo" + '\0';
    String input2 = "foo";
    println(input);
    println("input:");
    printBytes(input.getBytes());
    println("input2:");
    printBytes(input2.getBytes());
    String testValue = input.replaceAll("\u0000", "");
    println("testValue:");
    printBytes(testValue.getBytes());
    String testvalue2 = input2.replaceAll("\u0000","");
    println("testvalue2");
    printBytes(testvalue2.getBytes());
    assertFalse(input.equals(input2));
    assertTrue(testValue.equals(testvalue2));
  }
person avgvstvs    schedule 10.05.2014