Zastąp znak w określonym indeksie w ciągu?

382

Próbuję zastąpić znak w określonym indeksie w ciągu.

To co robię to:

String myName = "domanokz";
myName.charAt(4) = 'x';

To daje błąd. Czy jest na to jakaś metoda?

dpp
źródło
12
Zdaję sobie sprawę z tego, że odpowiedziano na śmierć, ale warto zauważyć, że nigdy nie wolno przypisywać wyniku wywołania funkcji w java. Nie ma takich rzeczy jak odwołania do C (?) I C ++.
ApproachingDarknessFish
1
@ValekHalfHeart w VB, używasz nawiasów, aby uzyskać dostęp do indeksu tablicy, co może być powodem, że jestem zdezorientowany, kiedy zaczynałem w Javie: D
dpp
@ApproachingDarknessFish Nie jestem pewien, co masz na myśli, mówiąc, że „nigdy nie wolno przypisywać wyniku wywołania funkcji w java”. Na pewno dasz radę double r = Math.sin(3.14)? Jak to się ma do tego pytania? Dzięki.
flow2k
1
@ flow2k Och Jezu, stary komentarz, więc nie można edytować, ale to literówka, należy powiedzieć, że „nigdy nie wolno przypisać do wyniku wywołania funkcji w Javie”. Czyli możesz napisać „foo = bar ();” ale nigdy „bar () = foo;”.
ApproachingDarknessFish
Dzięki za wyjaśnienie @ApproachingDarknessFish. Myślę, że byłoby dziwnie przypisać coś do wyniku funkcji - czy istnieją języki, które na to pozwalają? Zastanawiam się, jaki byłby przypadek użycia.
flow2k

Odpowiedzi:

566

Ciągi są niezmienne w Javie. Nie możesz ich zmienić.

Musisz utworzyć nowy ciąg z zastąpionym znakiem.

String myName = "domanokz";
String newName = myName.substring(0,4)+'x'+myName.substring(5);

Lub możesz użyć StringBuilder:

StringBuilder myName = new StringBuilder("domanokz");
myName.setCharAt(4, 'x');

System.out.println(myName);
Petar Iwanow
źródło
3
Ach, masz na myśli replacemetodę, która nie zmodyfikuje ciągu, ale zwróci tylko nowy ciąg?
dpp,
1
To trochę skomplikowane, panie Petar. Czy to najlepszy sposób, aby to zrobić? Ach, słyszałem wcześniej o StringBuilder, czy to coś zmienia? Czy da mi to łatwiejszą metodę?
dpp,
158

Zamień ciąg znaków na char [], zamień literę na indeks, a następnie przekonwertuj tablicę z powrotem na ciąg znaków.

String myName = "domanokz";
char[] myNameChars = myName.toCharArray();
myNameChars[4] = 'x';
myName = String.valueOf(myNameChars);
16 kropek
źródło
1
Uwielbiam to rozwiązanie. Skończyło się na zmianie trzeciego wiersza na myNameChars [index] = character.toCharArray () [0]; dla uproszczenia. Niezłe rozwiązanie.
Dale
2
wygląda znacznie lepiej niż drugi brzydszymyName.substring(0,4)+'x'+myName.substring(5);
user924
To jest o wiele prostsze
Shiva Acharjee
19

Stringto niezmienna klasa w java. Każda metoda, która wydaje się ją modyfikować, zawsze zwraca nowy obiekt łańcucha z modyfikacją.

Jeśli chcesz manipulować ciągiem, rozważ StringBuilderlub StringBufferw przypadku, gdy potrzebujesz bezpieczeństwa wątku.

bez nazwy
źródło
12

Zgadzam się z Petarem Iwanowem, ale najlepiej wdrożyć w następujący sposób:

public String replace(String str, int index, char replace){     
    if(str==null){
        return str;
    }else if(index<0 || index>=str.length()){
        return str;
    }
    char[] chars = str.toCharArray();
    chars[index] = replace;
    return String.valueOf(chars);       
}
Leninkumar Koppoju
źródło
21
a co czyni twoje rozwiązanie lepszym?
dpp
6

Jak już tu wcześniej odpowiedziano, Stringinstancje są niezmienne . StringBufferi StringBuildermożna je modyfikować i nadają się do tego celu, niezależnie od tego, czy chcesz być bezpieczny dla wątków, czy nie.

Istnieje jednak sposób na zmodyfikowanie ciągu, ale nigdy nie poleciłbym go, ponieważ jest on niebezpieczny, zawodny i można go uznać za oszustwo: można użyć odbicia do zmodyfikowania wewnętrznej chartablicy zawierającej obiekt String. Odbicie pozwala na dostęp do pól i metod, które zwykle są ukryte w bieżącym zakresie (metody prywatne lub pola z innej klasy ...).

public static void main(String[] args) {
    String text = "This is a test";
    try {
        //String.value is the array of char (char[])
        //that contains the text of the String
        Field valueField = String.class.getDeclaredField("value");
        //String.value is a private variable so it must be set as accessible 
        //to read and/or to modify its value
        valueField.setAccessible(true);
        //now we get the array the String instance is actually using
        char[] value = (char[])valueField.get(text);
        //The 13rd character is the "s" of the word "Test"
        value[12]='x';
        //We display the string which should be "This is a text"
        System.out.println(text);
    } catch (NoSuchFieldException | SecurityException e) {
        e.printStackTrace();
    } catch (IllegalArgumentException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    }
}
C. szampan
źródło
4

Możesz zastąpić ciąg w następujący sposób:

String myName = "halftime";
myName = myName.substring(0,4)+'x'+myName.substring(5);  

Zauważ, że ciąg myNamewystępuje w obu liniach i po obu stronach drugiej linii.

Dlatego, mimo że ciągi technicznie mogą być niezmienne, w praktyce można je traktować jako edytowalne, zastępując je.

CodeMed
źródło
Nie doceniłem twojej odpowiedzi, ale muszę przyznać, że mam problem z terminem „nadpisuj” (choć myślę, że zgadzamy się z tą koncepcją). Sam obiekt pozostaje niezmieniony. Po prostu spraw, aby zmienna odwoływała się do innego obiektu. Przy okazji warto wspomnieć, że w swoim przykładzie tworzysz co najmniej cztery instancje String.
C.Champagne
0

Pierwszą rzeczą, którą powinienem zauważyć, charAtjest metoda i przypisanie jej wartości za pomocą znaku równości nic nie da. Jeśli ciąg jest niezmienny, charAtmetoda, aby dokonać zmiany w obiekcie ciągu, musi otrzymać argument zawierający nowy znak. Niestety, ciąg jest niezmienny. Aby zmodyfikować ciąg, musiałem użyć StringBuilder zgodnie z sugestią pana Petara Iwanowa.

dpp
źródło
-7

to zadziała

   String myName="domanokz";
   String p=myName.replace(myName.charAt(4),'x');
   System.out.println(p);

Wyjście: domaxokz

Diabolus Infernalis
źródło
1
chociaż zdecydowanie nie znoszę tej metody umożliwienia „edytowalności” prac innych w tej witrynie StackOverFlow. całkowicie niesprawiedliwe: /
Diabolus Infernalis
2
Błąd składni. I nawet jeśli poprawione, powiedzmy, że chcę zastąpić pierwsze „o” na „x”, drugie „o” również zostanie zastąpione.
dpp
2
Zastąpi to wszystkie znaki, które są takie same jak charAt 4.
Shripad Bhat
1
Problem: myName.replace(myName.charAt(5),'x')da ci dxmanxkz, co prawdopodobnie nie jest wymagane.
Dawood ibn Kareem