Низ 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 = "¼"

test2 = "½"

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

Може ли някой да обясни защо test3 става "½"?


person Johan Nordli    schedule 19.12.2013    source източник
comment
Направете предупреждение(я); точно преди да извършите третата replaceAll. Вижте каква стойност идва.   -  person prograhammer    schedule 19.12.2013


Отговори (7)


Вие използвате replaceAll(), който приема регулярен израз. В regex-land . означава "всеки знак". Използвайте 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
@Bathsheba Радвам се да чуя това :) - person Adam Arold; 08.01.2014

Функцията replace all интерпретира първия аргумент като регулярен израз. „.5“ като регулярен израз ще съответства на всичко, последвано от 5, като вашия string 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 по време на компилиране можете да добавите флаг 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