Metoda zamiany ciągu nie zastępuje znaków

79

Mam zdanie, które jest przekazywane jako ciąg i zastępuję słowo „i” i chcę je zamienić na „”. I nie zastępuje słowa „i” spacjami. Poniżej znajduje się przykład mojej logiki. A kiedy debuguję to, logika wpada w zdanie. Zamień.

String sentence = "Define, Measure, Analyze, Design and Verify"
if (sentence.contains("and")){
    sentence.replace("and", " ");
}

Czy jest coś, czego mi tu brakuje.

ignamy
źródło
33
Ciągi znaków są niezmienne.
Matt Ball

Odpowiedzi:

171

A kiedy debuguję to, logika wpada w zdanie. Zamień.

Tak, a następnie odrzucasz wartość zwracaną.

Ciągi znaków w Javie są niezmienne - wywołanie replacenie zmienia zawartości istniejącego ciągu - zwraca nowy ciąg z modyfikacjami. Więc chcesz:

sentence = sentence.replace("and", " ");

Odnosi się to do wszystkich metod w String ( substring, toLowerCaseetc). Żaden z nich nie zmienia zawartości ciągu.

Zwróć uwagę, że tak naprawdę nie musisz tego robić w stanie - w końcu, jeśli zdanie nie zawiera "and", zastąpienie nie zaszkodzi:

String sentence = "Define, Measure, Analyze, Design and Verify";
sentence = sentence.replace("and", " ");
Jon Skeet
źródło
2
Muszę cię wezwać, żebyś odpowiedział na dupka, zamiast głosować za zamknięciem. Ten problem był już wcześniej zadawany i odpowiadany tak wiele razy - o co chodzi, Jon?
Matt Ball
2
@MattBall Chociaż zgadzam się, że pytanie było zadawane wielokrotnie, myślę, że jest to lepsza odpowiedź, IHMO
MadProgrammer
20
@MattBall: Jak to często bywa, szybciej jest mi udzielić dobrej, kompletnej odpowiedzi niż znaleźć duplikat, który również ma dobrą odpowiedź. Uważam (nieco egoistycznie, trzeba przyznać), że moja odpowiedź tutaj jest lepsza niż ta zaakceptowana w duplikacie, który znalazłeś, co nie ma nawet technicznego sensu. („Musisz sprawić, aby Twój łańcuch faktycznie odpowiadał zmianom, które wprowadzasz do łańcucha” - co?) Dodatkowo chciałem zwrócić uwagę na aspekt dotyczący braku konieczności sprawdzania najpierw zawartości.
Jon Skeet
Mając czas na przemyślenie tego, uważam, że to była lepsza odpowiedź.
ignamy
68

Ciągi znakówniezmienne , co oznacza, że ​​ich zawartość nie może się zmienić. Kiedy dzwonisz replace(this,that), otrzymujesz całkowicie nowy ciąg. Jeśli chcesz zachować tę nową kopię, musisz przypisać ją do zmiennej. Możesz nadpisać stare odniesienie (a la sentence = sentence.replace(this,that)lub nowe odniesienie, jak widać poniżej:

public class Test{

    public static void main(String[] args) {

        String sentence = "Define, Measure, Analyze, Design and Verify";

        String replaced = sentence.replace("and", "");
        System.out.println(replaced);

    }
}

Na marginesie, zwróć uwagę, że usunąłem contains()czek, ponieważ jest to niepotrzebne wezwanie. Jeśli go nie zawiera, zamiennik po prostu nie dokona żadnej wymiany. Chciałbyś, aby ta metoda zawierała tylko wtedy, gdy wymieniasz inny niż rzeczywisty stan, który sprawdzasz.

Kumar Vivek Mitra
źródło
41
Z tekstu tej odpowiedzi wynika, że ​​to contains()wezwanie powodowało problem - nie było. To był niepotrzebny telefon, ale tak naprawdę nie spowodował żadnych problemów. Problem wynikał z zignorowania zwracanej wartości replace, która nie została w ogóle wyjaśniona w odpowiedzi.
Jon Skeet
@ Panie Jon Skeet, bardzo mi przykro, jeśli z tekstu odpowiedzi wynika na odwrót ... ale kiedy powiedziałem, że nie jest to wymagane, miałem na myśli, że to niepotrzebne .... dobrze, uwzględnię to w odpowiedzi to bardziej oczywiste .....
Kumar Vivek Mitra
czy nie byłoby lepiej, gdybyś to zrobiłsentence.replace(" and", ",");
Khaled.K
@JonSkeet i inni - dodałem akapit, który faktycznie wyjaśnia, co się dzieje, i przeniosłem wprowadzający w błąd tekst na koniec, ponieważ jest on raczej zbędny w stosunku do prawdziwego problemu.
corsiKa
3
@corsiKa: Szczerze mówiąc, nie zrobiłbym tego jako edycji istniejącej odpowiedzi przez kogoś innego. To dość znacząco zmienia znaczenie odpowiedzi.
Jon Skeet,
9

Nie robisz nic ze zwracaną wartością replace. Musisz przypisać wynik metody, czyli nową String:

sentence = sentence.replace("and", " ");

A Stringjest niezmienny w java. Metody takie jak replacezwracają nowy plikString .

Twój containstest jest niepotrzebny: replacepo prostu nie będzie działać, jeśli nie ma egzemplarzy tekstu do zastąpienia.

pb2q
źródło
Moja logika zawierająca jest potrzebna, ponieważ są przypadki, w których nie chcę tego zastępować. Logika nie jest dokładnie taka, użyłem tego tylko jako przykładu.
ignamy
@MarkBasler: Twoja logika zawierająca nie jest potrzebna dla próbki, którą podałeś, więc nie powinieneś jej uwzględniać. Dobre pytania powinny zawierać tylko to, czego potrzebują, aby pokazać problem - dodając kod, który był bezcelowy w przedstawionej sytuacji, dodałeś do pytania rozproszenie.
Jon Skeet
Martwiłem się zawartością, byłem zainteresowany wymianą.
ignamy
Przy okazji zaznaczasz to jako duplikat i odpowiadasz. Zachowaj klasę.
ignamy
Cześć @MarkBasler: Próbowałem pomóc. Nie widzę konfliktu między tymi dwoma działaniami: Twój problem był niezwykle powszechny i ​​pojawiał się przez cały czas pytanie: ciągi znaków Java są niezmienne. Kiedy oznaczam pytanie jako zduplikowane, staram się poprawić jakość pytań i odpowiedzi tutaj, ale jednocześnie pozostawiając odpowiedź konkretną na Twoje pytanie, mam nadzieję, że udzielę Ci natychmiastowej pomocy, dostosowanej do Twojego przykładu . Może Ci się przydać to pytanie w meta .
pb2q
8

Powinieneś ponownie przypisać wynik zamiany, na przykład:

 sentence = sentence.replace("and", " ");

Należy pamiętać, że Stringklasa jest niezmienna , co oznacza, że wszystkie jej metody zwracają nowy ciąg i nigdy nie modyfikują oryginalnego ciągu w miejscu, więc wynik wywołania metody w instancji Stringmusi być przypisany do zmiennej lub używany natychmiast do zmiany, aby odniosły skutek.

Óscar López
źródło
Ciągi znaków powinny być niezmienne, ale w bibliotece String są błędy, które pozwalają na modyfikację oryginalnego ciągu.
ignamy
4
@MarkBasler: Hm, o jakich dokładnie błędach mówisz? A jeśli zdajesz sobie sprawę, że ciągi znaków są niezmienne, nie jest jasne, dlaczego spodziewałeś się, że Twój kod w ogóle zadziała ...
Jon Skeet
-1
package com.tulu.ds;

public class EmailSecurity {
    public static void main(String[] args) {
        System.out.println(returnSecuredEmailID("[email protected]"));
    }
    private static String returnSecuredEmailID(String email){
        String str=email.substring(1, email.lastIndexOf("@")-1);
        return email.replaceAll(email.substring(1, email.lastIndexOf("@")-1),replacewith(str.length(),"*"));
    }
    private static String replacewith(int length,String replace) {
        String finalStr="";
        for(int i=0;i<length;i++){
            finalStr+=replace;
        }
        return finalStr;
    }   
}
Tulu
źródło
3
Nie pisz odpowiedzi obejmujących tylko kod, zamiast tego wyjaśnij, w jaki sposób Twój kod rozwiązuje problem OP. Z recenzji
abccd