web-dev-qa-db-ja.com

文字列の一部を位置で置き換える方法は?

次の文字列があります:ABCDEFGHIJ

位置4から位置5までを文字列ZXで置き換える必要があります

次のようになります:ABCZXFGHIJ

しかし、string.replace("DE","ZX")では使用しないでください-positionで使用する必要があります

どうすればいいですか?

132
Gali

文字列の範囲を追加および削除する最も簡単な方法は、 StringBuilder を使用することです。

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

代わりに String.Substring を使用することもできますが、StringBuilderコードの方が読みやすいと思います。

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

ReplaceAt(int index、int length、string replace)

以下に、StringBuilderまたはSubstringを使用しない拡張メソッドを示します。このメソッドでは、置換文字列がソース文字列の長さを超えて拡張することもできます。

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

この関数を使用するときに、置換文字列全体でできるだけ多くの文字を置換する場合は、長さを置換文字列の長さに設定します。

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

それ以外の場合は、削除する文字の量を指定できます。

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

長さを0に指定すると、この関数は挿入関数と同様に機能します。

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

StringBuilderクラスを初期化する必要がなく、より基本的な操作を使用するため、これはより効率的だと思います。間違っている場合は修正してください。 :)

34
Nick Miller

String.Substring()(details here )を使用して、左側の部分、次に交換部分、次に右側の部分をカットします。正しくなるまでインデックスで遊んでください:)

何かのようなもの:

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

拡張方法として。

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

あなたはこれをリンクするものを試すことができます:

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

他の人が言及したように、Substring()関数には理由があります:

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

また、これをStringBuilderソリューションと比較して、900ティック対875を取得しました。したがって、わずかに遅くなります。

3
ja72

文字列にUnicode文字(絵文字など)が含まれている場合、他のすべての回答は機能しません

:絵文字「????」バイトに変換され、2文字に相当する重みが付けられます。そのため、文字列の先頭にUnicode文字が配置されている場合、offsetパラメーターがシフトされます)。

このトピック を使用して、ニックミラーのアルゴリズムを維持する位置によってStringInfoクラスをReplaceに拡張し、それを回避します。

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

この投稿の助けを借りて、追加の長さチェックを使用して次の関数を作成します

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

さらに別の

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

パフォーマンスに関心がある場合、ここで避けたいのは割り当てです。 .Net Core 2.1+(または、まだリリースされていない.Net Standard 2.1)を使用している場合は、 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));
        });
}

この方法は、他の方法よりも理解するのが困難ですが、呼び出しごとに1つのオブジェクト(新しく作成された文字列)のみを割り当てる唯一の方法です。

1
svick

次の要件を満たすソリューションを探していました。

  1. 単一の1行の式のみを使用する
  2. システム組み込みメソッドのみを使用します(カスタム実装ユーティリティは使用しません)

解決策1

私に最適なソリューションは次のとおりです。

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

これは StringBuilder.Replace(oldChar, newChar, position, count) を使用します

解決策2

私の要件を満たす他の解決策は、連結でSubstringを使用することです。

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

これも大丈夫です。 Iguess最初のパフォーマンスほど効率的ではありません(不要な文字列の連結のため)。しかし、早期最適化はすべての悪の根源です

あなたが最も好きなものを選んでください:)

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

私の解決策を説明しましょう。
2つの特定の位置(「位置4から位置5」)で2つの文字「Z」および「X」を使用して文字列を変更する問題文を与えます。質問は、位置インデックスを使用して文字列を変更することです文字列Replace()メソッドではなく(実際の文字列で一部の文字が繰り返される可能性があるため)、Substring()およびstring Concat()またはstring Remove()およびInsert()アプローチを使用するよりも、目標を達成するために最小限のアプローチを使用することをお勧めします。これらのソリューションはすべて同じ目標を達成するという目的を果たしますが、個人的な選択とミニマリストのアプローチで解決するという哲学に依存します。
上記のソリューションの話に戻って、stringStringBuilderを詳しく見ると、どちらも内部的に与えられた文字列を文字の配列として扱います。 StringBuilderの実装を見ると、「internal char[] m_ChunkChars;」のような内部変数を保持して、指定された文字列をキャプチャします。これは内部変数なので、同じものに直接アクセスすることはできません。外部の世界では、その文字配列にアクセスして変更できるようにするために、StringBuilderは以下のようなインデクサープロパティを介してそれらを公開します

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

上記の私のソリューションは、このインデクサー機能を活用して、IMOが効率的で最小限の内部的に維持されている文字配列を直接変更します。

ところで;上記のソリューションをより詳細に次のように書き換えることができます

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

このコンテキストでは、stringの場合、内部文字配列を公開する手段としてインデクサープロパティもありますが、この場合、文字列は本質的に不変であるため、Getterプロパティ(およびSetter)しかありません。それが、StringBuilderを使用して文字配列を変更する必要がある理由です。

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

そして最後になりましたが、この解決策は、事前に既知の位置インデックスを持つ少数の文字のみを置き換えるというこの特定の問題にのみ最適です。要件がかなり長い文字列を変更することである場合、つまり、変更する文字の数が多い場合には、最適ではない場合があります。

0
Asif

String.substr()を使用することをお勧めします。

このような:

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