Bagaimana cara mengganti bagian string dengan posisi?


155

Saya punya string ini: ABCDEFGHIJ

Saya perlu mengganti dari posisi 4 ke posisi 5 dengan string ZX

Ini akan terlihat seperti ini: ABCZXFGHIJ

Tetapi tidak untuk digunakan dengan string.replace("DE","ZX")- Saya perlu menggunakan dengan posisi

Bagaimana saya bisa melakukannya?


@TotZam - silakan periksa tanggal. Yang ini lebih tua dari yang Anda tautkan.
ToolmakerSteve

@ToolmakerSteve Saya biasanya melihat kualitas pertanyaan dan jawaban, bukan tanggal, seperti yang dikatakan di sini . Dalam hal ini, saya tampaknya telah membuat kesalahan dan mengklik yang salah untuk menandai sebagai duplikat, karena kualitas pertanyaan ini jelas lebih baik, dan saya telah menandai pertanyaan lainnya.
Tot Zam

@TotZam - ah, saya tidak tahu tentang rekomendasi itu - terima kasih telah menunjukkannya. (Meskipun membingungkan untuk melihat sesuatu yang lebih tua dilaporkan sebagai duplikat dari sesuatu yang lebih baru, jadi dalam kasus seperti itu, ada baiknya menjelaskan secara eksplisit bahwa Anda menandai sebagai duplikat pertanyaan TUA, karena yang tertaut memiliki jawaban yang lebih baik.)
ToolmakerSteve

Jawaban:


198

Cara termudah untuk menambah dan menghapus rentang dalam string adalah dengan menggunakan StringBuilder.

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

Alternatifnya adalah menggunakan String.Substring, tetapi saya pikir StringBuilderkodenya menjadi lebih mudah dibaca.


6
akan lebih baik membungkusnya dalam metode ekstensi :)
balexandre

Mengapa Anda menggunakan StringBuilder di sini? Periksa jawaban V4Vendetta, yang jauh lebih mudah dibaca ...
Fortega

1
@Fortega Hapus () dan Sisipkan () masing-masing buat dan kembalikan string baru. Pendekatan StringBuilder menghindari biaya tambahan ini dengan bekerja di dalam bagian memori yang dialokasikan sebelumnya dan menggerakkan karakter di dalamnya.
redcalx

@redcalx Itu benar, tetapi biaya tambahan diperkenalkan dengan memperkenalkan objek StringBuilder dan dengan mengurangi keterbacaan
Fortega

2
Apa gunanya menggunakan StringBuilder di sini, jika Anda memanggil Hapus dan Masukkan cara yang sama seperti V4Vendetta, tetapi ia melakukannya langsung pada string? Tampaknya kode berlebihan.
metabuddy

186
string s = "ABCDEFGH";
s= s.Remove(3, 2).Insert(3, "ZX");

17
Saya lebih suka ini daripada menginisialisasi StringBuilder baru (...). Terima kasih!
Michael Norgren

3
Saya tidak tahu mengapa seseorang akan menggunakan stringbuilder untuk operasi ini. Ini jawaban yang bagus
NappingRabbit

43

ReplaceAt (indeks int, panjang int, ganti string)

Berikut adalah metode ekstensi yang tidak menggunakan StringBuilder atau Substring. Metode ini juga memungkinkan string pengganti untuk memperpanjang melewati panjang string sumber.

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

Saat menggunakan fungsi ini, jika Anda ingin seluruh string pengganti mengganti karakter sebanyak mungkin, kemudian atur panjang ke panjang string pengganti:

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

Jika tidak, Anda dapat menentukan jumlah karakter yang akan dihapus:

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

Jika Anda menentukan panjangnya menjadi 0, maka fungsi ini bertindak seperti fungsi sisipan:

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

Saya kira ini lebih efisien karena kelas StringBuilder tidak perlu diinisialisasi dan karena menggunakan operasi yang lebih mendasar. Tolong koreksi saya jika saya salah. :)


5
Stringbuilder lebih efisien jika string lebih panjang dari, katakanlah 200 karakter.
Tim Schmelter

Tanpa stres. Bekerja lurus ke atas. Terima kasih
D_Edet

9

Gunakan String.Substring()(perincian di sini ) untuk memotong bagian kiri, lalu pengganti Anda, lalu bagian kanan. Mainkan dengan indeks sampai Anda melakukannya dengan benar :)

Sesuatu seperti:

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

2
Saya membuat tiga metode menggunakan tiga metode di atas (string.Remove / Insert, Stringbuilder.Remove / Insert dan jawaban Daniel's Substring, dan SubString adalah metode tercepat.
Francine DeGrood Taylor

7

Sebagai metode ekstensi.

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

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

Ini berhasil, Anda mungkin tidak ingin tkembali lagi.
Pierre

4

Jika Anda peduli dengan kinerja, maka hal yang ingin Anda hindari di sini adalah alokasi. Dan jika Anda berada di Net Inti 2.1 + (atau, belum belum pernah dirilis, Net Standard 2.1), maka Anda bisa, dengan menggunakan satu string.Createmetode :

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

Pendekatan ini lebih sulit dipahami daripada alternatifnya, tetapi hanya itu yang akan mengalokasikan hanya satu objek per panggilan: string yang baru dibuat.


3

Anda dapat mencoba sesuatu yang menghubungkan ini:

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

3

Seperti yang lain telah disebutkan Substring()fungsi ada karena suatu alasan:

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

Saya juga menghitung waktu ini terhadap StringBuildersolusi dan mendapatkan 900 tics vs 875. Jadi sedikit lebih lambat.


@ Aaron.S - tidak itu tidak. Dalam contoh saya "ABCDEFGHIJ"dan "ZX"panjangnya berbeda.
John Alexiou

3

Dan lagi

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

2

Dengan bantuan posting ini, saya membuat fungsi berikut dengan pemeriksaan panjang tambahan

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

Semua jawaban lain tidak berfungsi jika string berisi karakter Unicode char (seperti Emoji) karena karakter Unicode char lebih banyak byte daripada char.

Contoh : emoji '🎶' yang dikonversi menjadi byte, akan berbobot setara dengan 2 karakter. Jadi, jika karakter unicode diletakkan di awal string Anda, offsetparameter akan digeser).

Dengan topik ini , saya memperpanjang kelas StringInfo untuk Ganti dengan posisi menjaga algoritma Nick Miller untuk menghindari itu:

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

dotnetfiddle.net/l0dqS5 Saya tidak bisa mendapatkan metode lain untuk gagal di Unicode. Silakan ganti biola untuk menunjukkan kasus penggunaan Anda. Sangat tertarik dengan hasil.
Markus

1
@MarkusHooge Cobalah untuk menempatkan karakter unicode di awal string Anda seperti: dotnetfiddle.net/3V2K3Y . Anda hanya akan melihat baris terakhir berfungsi dengan baik dan menempatkan char ke posisi ke-4 (dalam kasus lain, unicode char membutuhkan waktu 2 char)
GGO

Anda benar, tidak jelas. Saya memperbarui jawaban saya untuk menambahkan lebih banyak penjelasan mengapa jawaban yang lain tidak berfungsi
GGO

1

Saya mencari solusi dengan persyaratan sebagai berikut:

  1. gunakan hanya satu, ekspresi satu baris
  2. hanya menggunakan metode builtin sistem (tidak ada utilitas yang diterapkan kustom)

Solusi 1

Solusi yang paling cocok untuk saya adalah ini:

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

Ini menggunakan StringBuilder.Replace(oldChar, newChar, position, count)

Solusi 2

Solusi lain yang memenuhi persyaratan saya adalah digunakan Substringdengan penggabungan:

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

Ini juga OK. saya kira itu tidak seefisien kinerja pertama yang bijaksana (karena penggabungan string yang tidak perlu). Tetapi optimasi prematur adalah akar dari semua kejahatan .

Jadi pilih salah satu yang paling Anda sukai :)


Solusi 2 berfungsi tetapi membutuhkan koreksi: string newString = oldStr.Substring (0, i) + c + oldString.Substring (i + 1, oldString.Length- (i +1));
Yura G

0

Lebih baik menggunakan String.substr().

Seperti ini:

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

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

Biarkan saya menjelaskan solusi saya.
Diberikan pernyataan masalah mengubah string dalam dua posisi spesifiknya ("posisi 4 ke posisi 5") dengan dua karakter 'Z' dan 'X' dan yang diminta adalah menggunakan indeks posisi untuk mengubah string dan bukan string. Ganti ( ) metode (mungkin karena kemungkinan pengulangan beberapa karakter dalam string aktual), saya lebih suka menggunakan pendekatan minimalis untuk mencapai tujuan menggunakan Substring()dan string Concat()atau string Remove()dan Insert()pendekatan. Meskipun semua solusi itu akan melayani tujuan dalam mencapai tujuan yang sama, tetapi itu hanya tergantung pada pilihan pribadi dan filosofi penyelesaian dengan pendekatan minimalis.
Kembali ke solusi saya sebutkan di atas, jika kita melihat lebih dekatstring danStringBuilder, keduanya secara internal memperlakukan string yang diberikan sebagai array karakter. Jika kita melihat implementasi StringBuilderitu mempertahankan sesuatu variabel internal seperti " internal char[] m_ChunkChars;" untuk menangkap string yang diberikan. Sekarang karena ini adalah variabel internal, kami tidak dapat langsung mengaksesnya. Untuk dunia eksternal, untuk dapat mengakses dan mengubah array karakter itu, StringBuildermengekspos mereka melalui properti pengindeks yang terlihat seperti di bawah ini

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

Solusi saya yang disebutkan di atas memanfaatkan kemampuan pengindeksan ini untuk secara langsung mengubah susunan karakter yang dipertahankan secara internal yang IMO efisien dan minimalis.

BTW; kita dapat menulis ulang solusi di atas dengan lebih rumit seperti di bawah ini

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

Dalam konteks ini juga ingin menyebutkan bahwa dalam kasus stringitu juga memiliki properti pengindeks sebagai sarana untuk mengekspos array karakter internal, tetapi dalam kasus ini hanya memiliki properti Getter (dan tidak ada Setter) karena string tidak dapat diubah pada dasarnya. Dan itu sebabnya kita perlu menggunakan StringBuilderuntuk mengubah array karakter.

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

Dan yang terakhir, namun tidak sedikit, solusi ini hanya paling cocok untuk masalah khusus ini di mana permintaannya adalah mengganti hanya beberapa karakter dengan indeks posisi yang dikenal di muka. Ini mungkin bukan yang paling cocok ketika persyaratannya adalah untuk mengubah string yang cukup panjang yaitu jumlah karakter yang harus diubah jumlahnya besar.


1
Harap edit jawaban Anda untuk menjelaskan bagaimana kode ini menjawab pertanyaan
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);

0

Berikut ini adalah metode ekstensi sederhana:

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

Gunakan seperti ini:

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

-2

Saya percaya cara paling sederhana adalah: (tanpa 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]);  
}

Ini berfungsi karena variabel tipe string dapat diperlakukan sebagai array variabel char. Misalnya, Anda dapat merujuk ke karakter kedua dari variabel string dengan nama "myString" sebagai myString [1]


Ini hanya berfungsi karena dalam contoh penulis stringkarakter yang akan diganti masing-masing hanya terjadi satu kali. Jika Anda menjalankan ini melawan, katakanlah, "DBCDEFGHIE"maka Anda dapatkan "ZBCZXFGHIX", yang bukan hasil yang diinginkan. Juga, saya tidak akan setuju bahwa ini lebih sederhana daripada non- StringBuildersolusi lain yang diposting dua setengah tahun yang lalu.
BACON
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.