Строка replaceAll (¾) в java

У меня действительно странная ошибка в моем java-коде, и я не могу понять, что не так.

Скажем, у меня есть этот код:

private void test()
{
    String test1 = replace("1.25");
    String test2 = replace("1.5");
    String test3 = replace("1.75");
}

private String replace(String s)
{
     s = s.replaceAll(".25", "¼");
     s = s.replaceAll(".5", "½");
     s = s.replaceAll(".75", "¾");
     return s;
}

Тогда результат будет:

тест1 = "¼"

тест2 = "½"

test3 = "½" ??????????

Может кто-нибудь объяснить, почему test3 становится «½»?


person Johan Nordli    schedule 19.12.2013    source источник
comment
Сделать предупреждение(я); непосредственно перед выполнением третьего replaceAll. Посмотрите, какое значение приходит.   -  person prograhammer    schedule 19.12.2013


Ответы (7)


Вы используете replaceAll(), который принимает регулярное выражение. В мире регулярных выражений . означает «любой символ». Используйте replace(), который работает с литеральными строками.

person arshajii    schedule 19.12.2013
comment
Или используйте Pattern#quote. - person Maroun; 19.12.2013
comment
@JohanNordli Нет проблем, рад, что смог помочь. - person arshajii; 19.12.2013

Потому что replaceAll принимает регулярное выражение. Это означает, что . интерпретируется как подстановочный знак, который также соответствует 7, так что .5 соответствует 75. Вы можете экранировать в регулярных выражениях, используя \, но обратите внимание, что это также строка, что означает, что вам придется экранировать дважды: поэтому replaceAll("\\.5", "½") сделает то, что вы хотели.

person Martin Ring    schedule 19.12.2013
comment
да, но на самом деле это не ложь и не не по теме в этом случае, самое меньшее, что можно сделать, это не голосовать или не голосовать, но отрицательный голос определенно не имеет значения, и между двумя ответами меньше одной минуты, что делает его отрицательным даже более неуместно. - person Kiwy; 19.12.2013

Проблема в том, что в регулярном выражении . означает любой символ. replaceAll принимает регулярное выражение в качестве параметра, поэтому вам следует использовать другие средства, такие как replace.

person Adam Arold    schedule 19.12.2013
comment
Я не видел его ответа, когда писал свой. - person Adam Arold; 19.12.2013
comment
Я думаю, вам нужно принять счастливую таблетку :) - person Adam Arold; 19.12.2013
comment
Пара таблеток счастья позже и, поразмыслив, вы правы. Я отозвал свой отрицательный голос. - person Bathsheba; 20.12.2013
comment
@ Вирсавия Рад это слышать :) - person Adam Arold; 08.01.2014

Функция replace all интерпретирует первый аргумент как регулярное выражение. «.5» в качестве регулярного выражения будет соответствовать всему, за которым следует цифра 5, например ваша строка test2. Избегайте '.' символ с обратной косой чертой:

 s = s.replaceAll("\\.25", "¼");
person Slicedpan    schedule 19.12.2013
comment
Должна быть двойная обратная косая черта! - person Gyro Gearless; 19.12.2013
comment
Ты уверен? Обратная косая черта не является буквальной, она предназначена для экранирования . символ (должен признать, что я не пробовал это в Java, но другие реализации регулярных выражений позволяют это) - person Slicedpan; 19.12.2013
comment
О да, вы правы, потому что это строка, как объясняет @MartinRing - person Slicedpan; 19.12.2013

replaceAll использует регулярное выражение в качестве первого параметра, который необходимо найти, а точка . в регулярном выражении — это метасимвол, который будет соответствовать всем символам, кроме новой строки. Итак, когда вы используете

s = s.replaceAll(".5", "½");

на "1.75" .5 может соответствовать 75 (поскольку . соответствует всем). Так что после такого изменения

1.75 
  -- will become 
1.½ 

(обратите внимание, что 1.25 работает правильно только потому, что вы использовали .25 до .5)

Чтобы предотвратить такое поведение, вам нужно экранировать точку. Вы можете сделать это по

  • поместив \ перед ним (помните, что для создания литерала \ вам нужно написать его как "\\") "\\.",
  • поместите его в класс символов [.],
  • окружите его \Q и \E, которые обозначают начало и конец цитаты \\Q.\\E
  • окружение с помощью \Q и \E также можно сделать с помощью Pattern.quote(".")
  • В случае экземпляра шаблона при компиляции вы можете добавить флаг Pattern.LITERAL, чтобы все метасимволы использовались в литералах шаблона.

Если вы хотите, чтобы весь наш шаблон был простым литералом, вы можете использовать replace вместо replaceAll, который автоматически использует флаг Pattern.LITERAL и превращает все метасимволы регулярных выражений в простые литералы.

Итак, вы можете попробовать что-то вроде

return s.replaceAll("\\.25", "¼").replaceAll("\\.5", "½").replaceAll("\\.75", "¾");

или проще

return s.replace(".25", "¼").replace(".5", "½").replace(".75", "¾");
person Pshemo    schedule 19.12.2013
comment
это очень хорошо объясняет, спасибо, что нашли время и написали действительно хороший ответ - person Johan Nordli; 19.12.2013

Используйте String.replace() вместо String.replaceAll()

Делай так

    private String replace(String s)
    {
        s = s.replace(".25", "¼");
        s = s.replace(".5", "½");
        s = s.replace(".75", "¾");
        return s;
    }
person Prabhakaran Ramaswamy    schedule 19.12.2013

Первый параметр replaceAll() — это REGEX, а '.' означает любой символ в области REGEX.

person Paul Lo    schedule 19.12.2013