web-dev-qa-db-fra.com

Comment remplacer une partie de chaîne par position?

J'ai cette chaîne: ABCDEFGHIJ

Je dois remplacer de la position 4 à la position 5 par la chaîne ZX

Cela ressemblera à ceci: ABCZXFGHIJ

Mais ne pas utiliser avec string.replace("DE","ZX") - Je dois utiliser avec position

Comment puis-je le faire?

125
Gali

La méthode la plus simple pour ajouter et supprimer des plages dans une chaîne consiste à utiliser StringBuilder .

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

Une alternative consiste à utiliser String.Substring , mais je pense que le code StringBuilder devient plus lisible.

168
Albin Sunnanbo
string s = "ABCDEFGH";
s= s.Remove(3, 2).Insert(3, "ZX");
145
V4Vendetta

ReplaceAt (index int, longueur int, chaîne de remplacement)

Voici une méthode d'extension qui n'utilise pas StringBuilder ou Substring. Cette méthode permet également à la chaîne de remplacement de s'étendre au-delà de la longueur de la chaîne source.

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

Lorsque vous utilisez cette fonction, si vous souhaitez que la chaîne de remplacement complète remplace autant de caractères que possible, définissez longueur par la longueur de la chaîne de remplacement:

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

Sinon, vous pouvez spécifier le nombre de caractères à supprimer:

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

Si vous spécifiez la longueur à 0, cette fonction agit comme la fonction d'insertion:

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

Je suppose que cela est plus efficace puisque la classe StringBuilder n’a pas besoin d’être initialisée et qu’elle utilise davantage d’opérations de base. S'il vous plait corrigez moi si je me trompe. :)

32
Nick Miller

Utilisez String.Substring() (details here ) pour couper la partie gauche, puis votre pièce de rechange, puis la partie droite. Jouez avec les index jusqu'à ce que vous obteniez la bonne réponse :)

Quelque chose comme:

string replacement=original.Substring(0,start)+
    rep+original.Substring(start+rep.Length);
9
Daniel Mošmondor

En tant que méthode d'extension.

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();
    }
}
6
alykhalid
        string s = "ABCDEFG";
        string t = "st";
        s = s.Remove(4, t.Length);
        s = s.Insert(4, t);
5
Javed Akram

Vous pouvez essayer quelque chose lier ceci:

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

Comme d'autres ont mentionné la fonction Substring() est là pour une raison:

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

J'ai aussi synchronisé ceci avec la solution StringBuilder et obtenu 900 tics contre 875. Donc, c'est légèrement plus lent.

3
ja72

Toutes les autres réponses ne fonctionnent pas si la chaîne contient un caractère Unicode (comme Emojis).

Avec this topic , j'étend la classe StringInfo à Replace by position en conservant l'algorithme de Nick Miller

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) : ""
        ));
    }
}
3
GGO

Avec l'aide de ce post, je crée la fonction suivante avec des contrôles de longueur supplémentaires

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

Encore un autre

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

Je cherchais une solution avec les exigences suivantes:

  1. n'utilisez qu'une seule expression d'une ligne
  2. utilisez uniquement les méthodes internes du système (pas d'utilitaire personnalisé)

Solution 1

La solution qui me convient le mieux est la suivante:

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

Ceci utilise StringBuilder.Replace(oldChar, newChar, position, count)

Solution 2

L’autre solution qui répond à mes besoins est d’utiliser Substring avec concaténation:

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

C'est bien aussi. Je (suppose) ce n'est pas aussi efficace que le premier en termes de performances (en raison d'une concaténation de chaînes inutile). Mais l'optimisation prématurée est la racine de tout mal

Alors, choisissez celui que vous aimez le plus :)

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

Laissez-moi vous expliquer ma solution.
Compte tenu du problème posé par la modification d'une chaîne dans ses deux positions spécifiques ("position 4 à position 5") avec les caractères "Z" et "X" à deux caractères, la demande consiste à utiliser l'indice de position pour modifier la chaîne. et non pas la méthode de chaîne Replace () (peut-être à cause de la possibilité de répétition de certains caractères de la chaîne réelle), je préférerais utiliser une approche minimaliste pour atteindre l'objectif par rapport à l'utilisation de Substring() et de la chaîne Concat() ou de la chaîne Remove() et de l'approche Insert(). Toutes ces solutions serviront à atteindre le même objectif, mais cela dépend simplement du choix personnel et de la philosophie consistant à adopter une approche minimaliste.
Pour revenir à ma solution mentionnée ci-dessus, si nous examinons de plus près string et StringBuilder, tous les deux traitent en interne une chaîne donnée comme un tableau de caractères. Si nous examinons l'implémentation de StringBuilder, il conserve une variable interne du type "internal char[] m_ChunkChars;" pour capturer la chaîne donnée. Comme il s'agit d'une variable interne, nous ne pouvons pas accéder directement à la même chose. Pour que le monde externe puisse accéder et modifier ce tableau de caractères, StringBuilder les expose à travers la propriété indexer qui ressemble à quelque chose comme ci-dessous

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

Ma solution, mentionnée ci-dessus, tire parti de cette capacité de l'indexeur pour modifier directement le tableau de caractères maintenu en interne, ce qui est efficace et minimaliste.

BTW; nous pouvons réécrire la solution ci-dessus plus en détail quelque chose comme ci-dessous

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

Dans ce contexte, vous voudrez également mentionner que, dans le cas de string, la propriété indexer est également utilisée pour exposer son tableau de caractères interne, mais dans ce cas, elle n’a que la propriété Getter (et pas de Setter) car la chaîne est de nature immuable. Et c’est pourquoi nous devons utiliser StringBuilder pour modifier le tableau de caractères.

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

Enfin et surtout, cette solution convient parfaitement à ce problème spécifique, dans lequel il est demandé de ne remplacer que quelques caractères avec un index de position connu. Ce n’est peut-être pas la meilleure solution lorsque l’obligation est de modifier une chaîne assez longue, c'est-à-dire que le nombre de caractères à modifier est élevé.

0
Asif

Si vous vous souciez de la performance, vous devez éviter les allocations. Et si vous êtes sur .Net Core 2.1+ (ou sur le .Net Standard 2.1, non encore publié), vous pouvez, en utilisant la méthode string.Create :

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

Cette approche est plus difficile à comprendre que les alternatives, mais c’est la seule qui n’allouera qu’un seul objet par appel: la chaîne nouvellement créée.

0
svick

Il vaut mieux utiliser le String.substr()

Comme ça:

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