Cum se înlocuiește o parte a șirului de caractere cu poziția? (Programare, C#, String, Înlocuiți)

Gali a intrebat.

Am acest șir de caractere: ABCDEFGHIJ

Am nevoie să înlocuiesc de la poziția 4 la poziția 5 cu șirul ZX

Acesta va arăta astfel: ABCZXFGHIJ

Dar nu pentru a utiliza cu string.replace("DE","ZX") – Trebuie să folosesc cu poziția

Cum pot face acest lucru?

Comentarii

  • @TotZam – vă rugăm să verificați datele. Acest este mai veche decât cea pe care ai legat-o. –  > Por ToolmakerSteve.
  • @ToolmakerSteve De obicei, mă uit la calitatea întrebărilor și a răspunsurilor, nu la date, așa cum s-a spus că se face aici. În acest caz, se pare că am făcut o greșeală și am făcut clic pe cea greșită pentru a o marca ca fiind duplicat, deoarece calitatea acestei întrebări este evident mai bună, așa că am marcat cealaltă întrebare. –  > Por Tot Zam.
  • @TotZam – ah, nu știam de această recomandare – mulțumesc că mi-ai semnalat-o. (Deși este derutant să vezi ceva mai vechi raportat ca duplicat a ceva mai nou, așa că, într-un astfel de caz, ar merita să explici explicit că marchezi ca duplicat o întrebare mai VECHE, deoarece cea legată are răspunsuri mai bune). –  > Por ToolmakerSteve.
18 răspunsuri
Albin Sunnanbo

Cel mai simplu mod de a adăuga și elimina intervale într-un șir de caractere este de a utiliza funcția StringBuilder.

var theString = "ABCDEFGHIJ";
var aStringBuilder = new StringBuilder(theString);
aStringBuilder.Remove(3, 2);
aStringBuilder.Insert(3, "ZX");
theString = aStringBuilder.ToString();

O alternativă este să folosiți String.Substring, , dar cred că StringBuilder codul devine mai ușor de citit.

Comentarii

  • ar fi mai bine să o includem într-o metodă de extensie 🙂 –  > Por balexandre.
  • De ce folosești un StringBuilder aici? Verificați răspunsul lui V4Vendetta, care este mult mai ușor de citit… –  > Por Fortega.
  • @Fortega Remove() și Insert() creează și returnează fiecare un nou șir de caractere. Abordarea StringBuilder evită acest cost suplimentar prin faptul că lucrează într-o secțiune pre-alocată de memorie și deplasează caracterele în interiorul acesteia. –  > Por redcalx.
  • @redcalx Este adevărat, dar este introdus un cost suplimentar prin introducerea unui obiect StringBuilder și prin reducerea lizibilității –  > Por Fortega.
  • Ce rost are să folosești StringBuilder aici, dacă tu apelezi Remove și Insert la fel ca V4Vendetta, dar el o face direct pe șir? Pare a fi un cod redundant. –  > Por metabuddy.
V4Vendetta
string s = "ABCDEFGH";
s= s.Remove(3, 2).Insert(3, "ZX");

Comentarii

    21

  • Prefer acest lucru decât să inițializez un nou StringBuilder(…). Mulțumesc! –  > Por Michael Norgren.
  • Nu știu de ce ar folosi cineva Stringbuilder pentru această operațiune. Acesta este un răspuns bun –  > Por NappingRabbit.
Nicholas Miller

ReplaceAt(int index, int length, string replace)

Iată o metodă de extensie care nu folosește StringBuilder sau Substring. Această metodă permite, de asemenea, ca șirul de înlocuire să se extindă dincolo de lungimea șirului sursă.

//// str - the source string
//// index- the start location to replace at (0-based)
//// length - the number of characters to be removed before inserting
//// replace - the string that is replacing characters
public static string ReplaceAt(this string str, int index, int length, string replace)
{
    return str.Remove(index, Math.Min(length, str.Length - index))
            .Insert(index, replace);
}

Atunci când utilizați această funcție, dacă doriți ca întregul șir de înlocuire să înlocuiască cât mai multe caractere posibil, setați length la lungimea șirului de înlocuire:

"0123456789".ReplaceAt(7, 5, "Hello") = "0123456Hello"

În caz contrar, puteți specifica numărul de caractere care vor fi eliminate:

"0123456789".ReplaceAt(2, 2, "Hello") = "01Hello456789"

Dacă specificați că lungimea este 0, atunci această funcție se comportă la fel ca funcția de inserare:

"0123456789".ReplaceAt(4, 0, "Hello") = "0123Hello456789"

Cred că este mai eficientă, deoarece clasa StringBuilder nu trebuie inițializată și deoarece utilizează mai multe operații de bază. Vă rog să mă corectați dacă mă înșel. 🙂

Comentarii

  • Stringbuilder este mai eficient dacă șirul este mai lung de, să zicem, 200 de caractere. –  > Por Tim Schmelter.
  • Fără stres. A funcționat direct. Mulțumiri –  > Por D_Edet.
Daniel Mošmondor

Utilizați String.Substring() (detalii aici) pentru a tăia partea stângă, apoi înlocuitorul tău, apoi partea dreaptă. Joacă-te cu indicii până când reușești 🙂

Ceva de genul:

string replacement=original.Substring(0,start)+
    rep+original.Substring(start+rep.Length);

Comentarii

  • Am creat trei metode folosind cele trei metode de mai sus (string.Remove/Insert, Stringbuilder.Remove/Insert și răspunsul Substring al lui Daniel, iar SubString a fost cea mai rapidă metodă. –  > Por Francine DeGrood Taylor.
Ali Khalid

Ca metodă de extensie.

public static class StringBuilderExtension
{
    public static string SubsituteString(this string OriginalStr, int index, int length, string SubsituteStr)
    {
        return new StringBuilder(OriginalStr).Remove(index, length).Insert(index, SubsituteStr).ToString();
    }
}

svick

Dacă vă pasă de performanță, atunci lucrul pe care doriți să îl evitați aici sunt alocările. Și dacă aveți .Net Core 2.1+ (sau .Net Standard 2.1, încă nepublicat), puteți, folosind string.Create metoda:

public static string ReplaceAt(this string str, int index, int length, string replace)
{
    return string.Create(str.Length - length + replace.Length, (str, index, length, replace),
        (span, state) =>
        {
            state.str.AsSpan().Slice(0, state.index).CopyTo(span);
            state.replace.AsSpan().CopyTo(span.Slice(state.index));
            state.str.AsSpan().Slice(state.index + state.length).CopyTo(span.Slice(state.index + state.replace.Length));
        });
}

Această abordare este mai greu de înțeles decât alternativele, dar este singura care va aloca un singur obiect la fiecare apel: șirul nou creat.

Javed Akram
        string s = "ABCDEFG";
        string t = "st";
        s = s.Remove(4, t.Length);
        s = s.Insert(4, t);

Comentarii

  • Acest lucru funcționează, probabil că nu doriți să puneți t din nou la loc. –  > Por Pierre.
MBU

Ați putea încerca ceva link acest lucru:

string str = "ABCDEFGHIJ";
str = str.Substring(0, 2) + "ZX" + str.Substring(5);

John Alexiou

Așa cum au menționat și alții Substring() este acolo cu un motiv:

static void Main(string[] args)
{
    string input = "ABCDEFGHIJ";

    string output = input.Overwrite(3, "ZX"); // 4th position has index 3
    // ABCZXFGHIJ
}

public static string Overwrite(this string text, int position, string new_text)
{
    return text.Substring(0, position) + new_text + text.Substring(position + new_text.Length);
}

De asemenea, am cronometrat acest lucru cu StringBuilder soluție și am obținut 900 de ticuri față de 875. Deci este ușor mai lent.

Comentarii

  • @Aaron.S – nu, nu este așa. În exemplul meu "ABCDEFGHIJ" și "ZX" sunt de lungimi diferite. –  > Por John Alexiou.
Stijn Van Antwerpen

Încă una

    public static string ReplaceAtPosition(this string self, int position, string newValue)        
    {
        return self.Remove(position, newValue.Length).Insert(position, newValue); 
    }

Hassan

Cu ajutorul acestei postări, am creat următoarea funcție cu verificări suplimentare de lungime

public string ReplaceStringByIndex(string original, string replaceWith, int replaceIndex)
{
    if (original.Length >= (replaceIndex + replaceWith.Length))
    {
        StringBuilder rev = new StringBuilder(original);
        rev.Remove(replaceIndex, replaceWith.Length);
        rev.Insert(replaceIndex, replaceWith);
        return rev.ToString();
    }
    else
    {
        throw new Exception("Wrong lengths for the operation");
    }
}

GGO

Toate celelalte răspunsuri nu funcționează dacă șirul conține caractere Unicode (cum ar fi Emojis) deoarece un caracter Unicode cântărește mai mulți octeți decât un caracter.

Exemplu : emoji ‘ ‘ convertit în bytes, va cântări echivalentul a 2 caractere. Așadar, dacă caracterul Unicode este plasat la începutul șirului dvs, offset va fi decalat).

Cu acest subiect, am extins clasa StringInfo pentru a înlocui prin poziție, păstrând algoritmul lui Nick Miller pentru a evita acest lucru:

public static class StringInfoUtils
{
    public static string ReplaceByPosition(this string str, string replaceBy, int offset, int count)
    {
        return new StringInfo(str).ReplaceByPosition(replaceBy, offset, count).String;
    }

    public static StringInfo ReplaceByPosition(this StringInfo str, string replaceBy, int offset, int count)
    {
        return str.RemoveByTextElements(offset, count).InsertByTextElements(offset, replaceBy);
    }

    public static StringInfo RemoveByTextElements(this StringInfo str, int offset, int count)
    {
        return new StringInfo(string.Concat(
            str.SubstringByTextElements(0, offset),
            offset + count < str.LengthInTextElements
                ? str.SubstringByTextElements(offset + count, str.LengthInTextElements - count - offset)
                : ""
            ));
    }
    public static StringInfo InsertByTextElements(this StringInfo str, int offset, string insertStr)
    {
        if (string.IsNullOrEmpty(str?.String))
            return new StringInfo(insertStr);
        return new StringInfo(string.Concat(
            str.SubstringByTextElements(0, offset),
            insertStr,
            str.LengthInTextElements - offset > 0 ? str.SubstringByTextElements(offset, str.LengthInTextElements - offset) : ""
        ));
    }
}

Comentarii

  • dotnetfiddle.net/l0dqS5 Nu am reușit să fac ca alte metode să eșueze pe Unicode. Vă rugăm să modificați vioara pentru a vă demonstra cazul de utilizare. Foarte interesat, în rezultate. –  > Por Markus.
  • @MarkusHooge Încercați să plasați caracterele Unicode la începutul șirului dvs. de caractere, cum ar fi : dotnetfiddle.net/3V2K3Y. Veți vedea că doar ultima linie funcționează bine și plasează caracterul la locul 4 (în celălalt caz, caracterul unicode are lungimea de 2 caractere) –  > Por GGO.
  • Aveți dreptate, nu este clar. Mi-am actualizat răspunsul pentru a adăuga mai multe explicații de ce nu funcționează celelalte răspunsuri –  > Por GGO.
KFL

Căutam o soluție cu următoarele cerințe:

  1. să utilizeze doar o singură expresie de o singură linie
  2. să utilizeze numai metode integrate în sistem (fără utilitate implementată la comandă)

Soluția 1

Soluția care mi se potrivește cel mai bine este următoarea:

// replace `oldString[i]` with `c`
string newString = new StringBuilder(oldString).Replace(oldString[i], c, i, 1).ToString();

Aceasta utilizează StringBuilder.Replace(oldChar, newChar, position, count)

Soluția 2

Cealaltă soluție care îmi satisface cerințele este să folosesc Substring cu concatenare:

string newString = oldStr.Substring(0, i) + c + oldString.Substring(i+1, oldString.Length);

Și aceasta este în regulă. I cred că că nu este la fel de eficientă ca prima soluție din punct de vedere al performanței (din cauza concatenării inutile a șirurilor de caractere). Dar optimizarea prematură este rădăcina tuturor relelor.

Așa că alegeți-o pe cea care vă place cel mai mult 🙂

Comentarii

  • Soluția 2 funcționează, dar necesită o corecție: string newString = oldString.Substring(0, i) + c + oldString.Substring(i+1, oldString.Length-(i+1)); –  > Por Yura G.
Varun Kumar

Este mai bine să folosiți String.substr().

Astfel:

ReplString = GivenStr.substr(0, PostostarRelStr)
           + GivenStr(PostostarRelStr, ReplString.lenght());

Asif
string myString = "ABCDEFGHIJ";
string modifiedString = new StringBuilder(myString){[3]='Z', [4]='X'}.ToString();

Permiteți-mi să vă explic soluția mea.
Având în vedere enunțul problemei de a modifica un șir de caractere în două poziții specifice („poziția 4 la poziția 5”) cu două caractere „Z” și „X” și solicitarea de a utiliza indexul de poziție pentru a modifica șirul de caractere și nu metoda Replace() (poate din cauza posibilității de repetare a unor caractere în șirul de caractere actual), aș prefera să folosesc o abordare minimalistă pentru a atinge obiectivul în loc să folosesc Substring() și string Concat() sau string Remove() și Insert() abordare. Cu toate că toate aceste soluții vor servi scopului de a atinge același obiectiv, dar depinde doar de alegerea personală și de filozofia de soluționare a problemei cu abordarea minimalistă.
Revenind la soluția mea menționată mai sus, dacă ne uităm mai atent la string și StringBuilder, ambele tratează intern un șir de caractere dat ca pe o matrice de caractere. Dacă ne uităm la implementarea lui StringBuilder aceasta menține o variabilă internă de tipul „internal char[] m_ChunkChars;” pentru a capta șirul dat. Acum, deoarece aceasta este o variabilă internă, nu o putem accesa direct. Pentru lumea externă, pentru a putea accesa și modifica acea matrice de caractere, StringBuilder le expune prin intermediul proprietății indexer, care arată ca mai jos

    [IndexerName("Chars")]
    public char this[int index]
    {
      get
      {
        StringBuilder stringBuilder = this;
        do
        {
          // … some code
            return stringBuilder.m_ChunkChars[index1];
          // … some more code
        }
      }
      set
      {
        StringBuilder stringBuilder = this;
        do
        {
            //… some code
            stringBuilder.m_ChunkChars[index1] = value;
            return;
            // …. Some more code
        }
      }
    }

Soluția mea menționată mai sus valorifică această capacitate de indexare pentru a modifica direct matricea de caractere întreținută intern, ceea ce, potrivit OMI, este eficient și minimalist.

BTW; putem rescrie soluția de mai sus în mod mai elaborat, ceva de genul următor

 string myString = "ABCDEFGHIJ";
 StringBuilder tempString = new StringBuilder(myString);
 tempString[3] = 'Z';
 tempString[4] = 'X';
 string modifiedString = tempString.ToString();

În acest context, aș dori, de asemenea, să menționez că în cazul în care string are, de asemenea, proprietatea indexer ca mijloc de expunere a matricei sale interne de caractere, dar în acest caz are doar proprietatea Getter (și nu Setter), deoarece șirul de caractere este imuabil prin natura sa. Acesta este motivul pentru care trebuie să folosim StringBuilder pentru a modifica matricea de caractere.

[IndexerName("Chars")]
public extern char this[int index] { [SecuritySafeCritical, __DynamicallyInvokable, MethodImpl(MethodImplOptions.InternalCall)] get; }

Și, nu în ultimul rând, această soluție este cea mai potrivită doar pentru această problemă specifică în care se solicită înlocuirea doar a câtorva caractere cu un indice de poziție cunoscut în avans. S-ar putea să nu fie cea mai potrivită atunci când cerința este de a modifica un șir de caractere destul de lung, adică atunci când numărul de caractere de modificat este mare.

Comentarii

  • Vă rugăm să vă modificați răspunsul pentru a explica cum răspunde acest cod la întrebare –  > Por tshimkus.
user1355816
String timestamp = "2019-09-18 21.42.05.000705";
String sub1 = timestamp.substring(0, 19).replace('.', ':'); 
String sub2 = timestamp.substring(19, timestamp.length());
System.out.println("Original String "+ timestamp);      
System.out.println("Replaced Value "+ sub1+sub2);

MovGP0

Iată o metodă simplă de extindere:

    public static class StringBuilderExtensions
    {
        public static StringBuilder Replace(this StringBuilder sb, int position, string newString)
            => sb.Replace(position, newString.Length, newString);

        public static StringBuilder Replace(this StringBuilder sb, int position, int length, string newString)
            => (newString.Length <= length)
                ? sb.Remove(position, newString.Length).Insert(position, newString)
                : sb.Remove(position, length).Insert(position, newString.Substring(0, length));
    }

Folosiți-o în felul următor:

var theString = new string(' ', 10);
var sb = new StringBuilder(theString);
sb.Replace(5, "foo");
return sb.ToString();

Sfou

Cred că cea mai simplă metodă ar fi aceasta:(fără stringbuilder)

string myString = "ABCDEFGHIJ";
char[] replacementChars = {'Z', 'X'};
byte j = 0;

for (byte i = 3; i <= 4; i++, j++)  
{                   
myString = myString.Replace(myString[i], replacementChars[j]);  
}

Acest lucru funcționează deoarece o variabilă de tip string poate fi tratată ca o matrice de variabile char.Puteți, de exemplu, să vă referiți la al doilea caracter al unei variabile string cu numele „myString” ca myString[1]

Comentarii

  • Acest lucru funcționează doar pentru că în exemplul autorului string caracterele care urmează să fie înlocuite apar fiecare o singură dată. Dacă executați acest lucru cu, să zicem, "DBCDEFGHIE" atunci veți obține "ZBCZXFGHIX", , ceea ce nu este rezultatul dorit. De asemenea, nu aș fi de acord că acest lucru este mai simplu decât celelalte variante care nu sunt de acord.StringBuilder soluții care au fost postate acum doi ani și jumătate. –  > Por Lance U. Matthews.