Wie ersetze ich einen Teil der Zeichenfolge durch die Position?

155

Ich habe diese Zeichenfolge: ABCDEFGHIJ

Ich muss von Position 4 auf Position 5 durch die Zeichenfolge ersetzen ZX

Es wird so aussehen: ABCZXFGHIJ

Aber nicht mit zu verwenden string.replace("DE","ZX")- ich muss mit Position verwenden

Wie kann ich es tun?

Gali
quelle
@TotZam - bitte überprüfen Sie die Daten. Dieser ist älter als der, den Sie verlinkt haben.
ToolmakerSteve
@ToolmakerSteve Ich sehe in der Regel auf die Qualität der Fragen und Antworten, nicht die Daten, die als tun hier . In diesem Fall habe ich anscheinend einen Fehler gemacht und auf den falschen geklickt, um ihn als Duplikat zu markieren, da die Qualität dieser Frage offensichtlich besser ist, und deshalb habe ich die andere Frage markiert.
Tot Zam
@TotZam - ah, ich wusste nichts über diese Empfehlung - danke, dass Sie darauf hingewiesen haben. (Obwohl es verwirrend ist, etwas Älteres als Duplikat von etwas Neuerem zu sehen, sollte in einem solchen Fall ausdrücklich erklärt werden, dass Sie eine ÄLTERE Frage als Duplikat markieren, da die verknüpfte Frage bessere Antworten hat.)
ToolmakerSteve

Antworten:

198

Der einfachste Weg, Bereiche in einer Zeichenfolge hinzuzufügen und zu entfernen, ist die Verwendung von StringBuilder.

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

Eine Alternative ist die Verwendung String.Substring, aber ich denke, der StringBuilderCode wird besser lesbar.

Albin Sunnanbo
quelle
6
wäre besser, das in eine Erweiterungsmethode zu
packen
Warum verwenden Sie hier einen StringBuilder? Überprüfen Sie V4Vendettas Antwort, die viel besser lesbar ist ...
Fortega
1
@Fortega Remove () und Insert () erstellen und geben jeweils eine neue Zeichenfolge zurück. Der StringBuilder-Ansatz vermeidet diese zusätzlichen Kosten, indem er in einem vorab zugewiesenen Speicherabschnitt arbeitet und Zeichen darin bewegt.
Redcalx
@redcalx Das stimmt, aber zusätzliche Kosten entstehen durch die Einführung eines StringBuilder-Objekts und durch die Verringerung der Lesbarkeit
Fortega
2
Was bringt es, StringBuilder hier zu verwenden, wenn Sie Remove and Insert auf die gleiche Weise wie V4Vendetta aufrufen, dies jedoch direkt für den String tun? Scheint redundanter Code.
Metabuddy
186
string s = "ABCDEFGH";
s= s.Remove(3, 2).Insert(3, "ZX");
V4Vendetta
quelle
17
Ich bevorzuge dies gegenüber der Initialisierung eines neuen StringBuilder (...). Vielen Dank!
Michael Norgren
3
Ich weiß nicht, warum jemand Stringbuilder für diese Operation verwenden würde. Dies ist eine gute Antwort
NappingRabbit
43

ReplaceAt (int index, int length, string replace)

Hier ist eine Erweiterungsmethode, die weder StringBuilder noch Teilzeichenfolge verwendet. Diese Methode ermöglicht es der Ersetzungszeichenfolge auch, sich über die Länge der Quellzeichenfolge hinaus zu erstrecken.

//// 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);
}

Wenn Sie bei Verwendung dieser Funktion möchten, dass die gesamte Ersatzzeichenfolge so viele Zeichen wie möglich ersetzt, setzen Sie die Länge auf die Länge der Ersatzzeichenfolge:

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

Andernfalls können Sie die Anzahl der Zeichen angeben, die entfernt werden sollen:

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

Wenn Sie die Länge auf 0 setzen, verhält sich diese Funktion genauso wie die Einfügefunktion:

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

Ich denke, dies ist effizienter, da die StringBuilder-Klasse nicht initialisiert werden muss und grundlegendere Operationen verwendet werden. Bitte korrigieren Sie mich, wenn ich falsch liege. :) :)

Nicholas Miller
quelle
5
Stringbuilder ist effizienter, wenn die Zeichenfolge länger als beispielsweise 200 Zeichen ist.
Tim Schmelter
Kein Stress. Gerade gearbeitet. Danke
D_Edet
9

Verwenden Sie String.Substring()(Details hier ), um das linke Teil, dann Ihren Ersatz und dann das rechte Teil zu schneiden. Spielen Sie mit Indizes, bis Sie es richtig machen :)

Etwas wie:

string replacement=original.Substring(0,start)+
    rep+original.Substring(start+rep.Length);
Daniel Mošmondor
quelle
2
Ich habe drei Methoden mit den oben genannten drei Methoden erstellt (string.Remove / Insert, Stringbuilder.Remove / Insert und Daniels Teilzeichenfolge, und SubString war die schnellste Methode.
Francine DeGrood Taylor
7

Als Erweiterungsmethode.

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();
    }
}
Ali Khalid
quelle
5
        string s = "ABCDEFG";
        string t = "st";
        s = s.Remove(4, t.Length);
        s = s.Insert(4, t);
Javed Akram
quelle
Dies funktioniert, Sie möchten wahrscheinlich nicht twieder zurücksetzen.
Pierre
4

Wenn Sie Wert auf Leistung legen, sollten Sie hier Zuweisungen vermeiden. Und wenn Sie auf .NET - Core - 2.1+ (oder, noch unveröffentlicht, .Net Standard 2.1), dann können Sie, unter Verwendung der string.CreateMethode :

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));
        });
}

Dieser Ansatz ist schwerer zu verstehen als die Alternativen, aber es ist der einzige, der nur ein Objekt pro Aufruf zuweist: die neu erstellte Zeichenfolge.

svick
quelle
3

Sie könnten versuchen, etwas zu verlinken:

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

Wie andere bereits erwähnt haben, gibt es die Substring()Funktion aus einem Grund:

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);
}

Außerdem habe ich dies gegen die StringBuilderLösung abgestimmt und 900 Tics gegen 875 erhalten. Es ist also etwas langsamer.

John Alexiou
quelle
@ Aaron.S - nein tut es nicht. In meinem Beispiel "ABCDEFGHIJ"und "ZX"sind unterschiedlich lang.
John Alexiou
3

Noch ein anderer

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

Mit Hilfe dieses Beitrags erstelle ich folgende Funktion mit zusätzlichen Längenprüfungen

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");
    }
}
Hassan
quelle
2

Alle anderen Antworten funktionieren nicht, wenn die Zeichenfolge Unicode-Zeichen enthält (wie Emojis), da ein Unicode-Zeichen mehr Bytes als ein Zeichen wiegt.

Beispiel : Das in Bytes konvertierte Emoji '🎶' gewichtet das Äquivalent von 2 Zeichen. Wenn also das Unicode-Zeichen am Anfang Ihrer Zeichenfolge steht, wird der offsetParameter verschoben.

Mit diesem Thema erweitere ich die StringInfo-Klasse auf Ersetzen, indem ich den Algorithmus von Nick Miller behalte, um Folgendes zu vermeiden:

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) : ""
        ));
    }
}
GGO
quelle
dotnetfiddle.net/l0dqS5 Andere Methoden konnten unter Unicode nicht fehlschlagen. Bitte ändern Sie die Geige, um Ihren Anwendungsfall zu demonstrieren. Sehr interessiert an Ergebnissen.
Markus
1
@MarkusHooge Versuchen Sie, die Unicode-Zeichen am Anfang Ihrer Zeichenfolge zu platzieren, z . B .: Dotnetfiddle.net/3V2K3Y . Sie werden sehen, dass nur die letzte Zeile gut funktioniert und das Zeichen auf den 4. Platz setzen (im anderen Fall benötigt Unicode-Zeichen 2 Zeichen Länge)
GGO
Du hast recht, es ist nicht klar. Ich habe meine Antwort aktualisiert, um weitere Erklärungen hinzuzufügen, warum die anderen Antworten nicht funktionieren
GGO
1

Ich suchte nach einer Lösung mit folgenden Anforderungen:

  1. Verwenden Sie nur einen einzigen einzeiligen Ausdruck
  2. Verwenden Sie nur systemintegrierte Methoden (kein benutzerdefiniertes Dienstprogramm).

Lösung 1

Die Lösung, die am besten zu mir passt, ist folgende:

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

Dies verwendet StringBuilder.Replace(oldChar, newChar, position, count)

Lösung 2

Die andere Lösung, die meine Anforderungen erfüllt, ist die Verwendung Substringmit Verkettung:

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

Das ist auch in Ordnung. Ich denke, es ist nicht so effizient wie das erste in Bezug auf die Leistung (aufgrund unnötiger Verkettung von Zeichenfolgen). Aber vorzeitige Optimierung ist die Wurzel allen Übels .

Also wähle die aus, die dir am besten gefällt :)

KFL
quelle
Lösung 2 funktioniert, erfordert jedoch eine Korrektur: Zeichenfolge newString = oldStr.Substring (0, i) + c + oldString.Substring (i + 1, oldString.Length- (i + 1));
Yura G
0

Es ist besser, die zu verwenden String.substr().

So was:

ReplString = GivenStr.substr(0, PostostarRelStr)
           + GivenStr(PostostarRelStr, ReplString.lenght());
Varun Kumar
quelle
0
string myString = "ABCDEFGHIJ";
string modifiedString = new StringBuilder(myString){[3]='Z', [4]='X'}.ToString();

Lassen Sie mich meine Lösung erklären.
Angesichts der Problemstellung, eine Zeichenfolge an ihren zwei spezifischen Positionen („Position 4 bis Position 5“) mit den beiden Zeichen 'Z' und 'X' zu ändern, wird gefragt, ob der Positionsindex zum Ändern der Zeichenfolge und nicht der Zeichenfolge Ersetzen ( ) Methode (möglicherweise aufgrund der Möglichkeit der Wiederholung einiger Zeichen in der tatsächlichen Zeichenfolge), würde ich es vorziehen, einen minimalistischen Ansatz zu verwenden, um das Ziel zu erreichen, anstatt eine Substring()Zeichenfolge Concat()oder eine Zeichenfolge Remove()und einen Insert()Ansatz zu verwenden. Obwohl all diese Lösungen dem Zweck dienen, dasselbe Ziel zu erreichen, hängt es nur von der persönlichen Wahl und der Philosophie ab, sich mit einem minimalistischen Ansatz abzufinden.
Kommen wir zurück oben auf meiner Lösung zu erwähnen, wenn wir einen genaueren Blick nehmen stringundStringBuilderBeide behandeln eine bestimmte Zeichenfolge intern als ein Array von Zeichen. Wenn wir uns die Implementierung ansehen StringBuilder, wird eine interne Variable wie " internal char[] m_ChunkChars;" beibehalten , um die angegebene Zeichenfolge zu erfassen. Da dies eine interne Variable ist, können wir nicht direkt darauf zugreifen. Damit die Außenwelt auf dieses Zeichenarray zugreifen und es ändern kann, werden StringBuildersie über die Indexer-Eigenschaft verfügbar gemacht, die wie folgt aussieht

    [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
        }
      }
    }

Meine oben erwähnte Lösung nutzt diese Indexerfunktion, um das intern verwaltete Zeichenarray, das IMO effizient und minimalistisch ist, direkt zu ändern.

Übrigens; Wir können die obige Lösung ausführlicher umschreiben, so etwas wie unten

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

In diesem Zusammenhang möchte stringich auch erwähnen, dass es in diesem Fall auch eine Indexer-Eigenschaft als Mittel zum Offenlegen seines internen Zeichenarrays gibt, in diesem Fall jedoch nur eine Getter-Eigenschaft (und keinen Setter), da die Zeichenfolge unveränderlich ist. Und deshalb müssen wir StringBuilderdas Zeichenarray ändern.

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

Und last but not least ist diese Lösung nur für dieses spezielle Problem am besten geeignet, bei dem nur wenige Zeichen im Voraus durch einen bekannten Positionsindex ersetzt werden müssen. Es ist möglicherweise nicht die beste Anpassung, wenn eine ziemlich lange Zeichenfolge geändert werden muss, dh die Anzahl der zu ändernden Zeichen ist groß.

Als ob
quelle
1
Bitte bearbeiten Sie Ihre Antwort, um zu erklären, wie dieser Code die Frage beantwortet
tshimkus
0
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);
user1355816
quelle
0

Hier ist eine einfache Erweiterungsmethode:

    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));
    }

Verwenden Sie es so:

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

Ich glaube, der einfachste Weg wäre folgender: (ohne 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]);  
}

Dies funktioniert, weil eine Variable vom Typ string als Array von Zeichenvariablen behandelt werden kann. Sie können beispielsweise das zweite Zeichen einer Zeichenfolgenvariablen mit dem Namen "myString" als myString [1] bezeichnen.

Sfou
quelle
Dies funktioniert nur, weil im Beispiel des Autors die stringzu ersetzenden Zeichen jeweils nur einmal vorkommen. Wenn Sie dies beispielsweise ausführen, erhalten "DBCDEFGHIE"Sie "ZBCZXFGHIX", was nicht das gewünschte Ergebnis ist. Ich würde auch nicht zustimmen, dass dies einfacher ist als die anderen Nicht-StringBuilder , die vor zweieinhalb Jahren veröffentlicht wurden.
Speck