C # - Cara termudah untuk menghapus kemunculan pertama substring dari string lain


88

Saya perlu menghapus kejadian pertama (dan HANYA yang pertama) dari string dari string lain.

Berikut adalah contoh penggantian string "\\Iteration". Ini:

ProjectName \\ Iteration \\ Release1 \\ Iteration1

akan menjadi ini:

ProjectName \\ Rilis1 \\ Iterasi1

Berikut beberapa kode yang melakukan ini:

const string removeString = "\\Iteration";
int index = sourceString.IndexOf(removeString);
int length = removeString.Length;
String startOfString = sourceString.Substring(0, index);
String endOfString = sourceString.Substring(index + length);
String cleanPath = startOfString + endOfString;

Sepertinya banyak kode.

Jadi pertanyaan saya adalah ini: Apakah ada cara yang lebih bersih / lebih mudah dibaca / lebih ringkas untuk melakukan ini?

Jawaban:


155
int index = sourceString.IndexOf(removeString);
string cleanPath = (index < 0)
    ? sourceString
    : sourceString.Remove(index, removeString.Length);

10
Jawaban ini mungkin rusak untuk string yang melibatkan karakter non-ASCII. Misalnya, di bawah budaya en-AS, ædan aedianggap setara. Mencoba menghapus paediadari Encyclopædiaakan melempar ArgumentOutOfRangeException, karena Anda mencoba menghapus 6 karakter saat substring yang cocok hanya berisi 5.
Douglas

6
Kita dapat memodifikasinya seperti ini: sourceString.IndexOf(removeString, StringComparison.Ordinal)untuk menghindari pengecualian.
Borislav Ivanov

30
string myString = sourceString.Remove(sourceString.IndexOf(removeString),removeString.Length);

EDIT: @OregonGhost benar. Saya sendiri akan memutuskan skrip dengan persyaratan untuk memeriksa kejadian seperti itu, tetapi saya beroperasi dengan asumsi bahwa string diberikan untuk dimiliki satu sama lain dengan beberapa persyaratan. Ada kemungkinan bahwa aturan penanganan pengecualian yang diwajibkan bisnis diharapkan dapat menangkap kemungkinan ini. Saya sendiri akan menggunakan beberapa baris tambahan untuk melakukan pemeriksaan bersyarat dan juga membuatnya sedikit lebih mudah dibaca oleh pengembang junior yang mungkin tidak meluangkan waktu untuk membacanya dengan cukup menyeluruh.


9
Ini akan macet jika removeString tidak terdapat dalam sourceString.
OregonGhost

27
sourceString.Replace(removeString, "");

18
String.Replace mengatakan bahwa itu " [r] eturns string baru di mana semua kemunculan string yang ditentukan dalam contoh saat ini diganti dengan string lain yang ditentukan ". OP ingin menggantikan kejadian pertama .
Wai Ha Lee

6
Selain itu, Anda harus menjelaskan sedikit jawaban Anda karena jawaban hanya kode tidak dapat diterima. Lihatlah jawaban lainnya, dan bandingkan dengan jawaban Anda untuk beberapa tip.
Wai Ha Lee

11

Menulis Tes TDD singkat untuk ini

    [TestMethod]
    public void Test()
    {
        var input = @"ProjectName\Iteration\Release1\Iteration1";
        var pattern = @"\\Iteration";

        var rgx = new Regex(pattern);
        var result = rgx.Replace(input, "", 1);

        Assert.IsTrue(result.Equals(@"ProjectName\Release1\Iteration1"));
    }

rgx.Replace (masukan, "", 1); mengatakan untuk mencari masukan apa pun yang cocok dengan pola, dengan "", 1 kali.


2
Seperti itu Anda memecahkan masalah. Pertimbangkan saja kinerja saat menggunakan regex untuk masalah seperti ini.
Thomas

7

Anda dapat menggunakan metode ekstensi untuk bersenang-senang. Biasanya saya tidak merekomendasikan melampirkan metode ekstensi ke kelas tujuan umum seperti string, tetapi seperti yang saya katakan ini menyenangkan. Saya meminjam jawaban @ Luke karena tidak ada gunanya menemukan kembali roda.

[Test]
public void Should_remove_first_occurrance_of_string() {

    var source = "ProjectName\\Iteration\\Release1\\Iteration1";

    Assert.That(
        source.RemoveFirst("\\Iteration"),
        Is.EqualTo("ProjectName\\Release1\\Iteration1"));
}

public static class StringExtensions {
    public static string RemoveFirst(this string source, string remove) {
        int index = source.IndexOf(remove);
        return (index < 0)
            ? source
            : source.Remove(index, remove.Length);
    }
}

3
Mengapa Anda biasanya tidak merekomendasikan untuk melampirkan metode ekstensi ke kelas tujuan umum seperti String? Apa kerugian nyata dari hal ini?
Teun Kooijman

1
Sangat mudah untuk membangun metode ekstensi untuk tujuan yang terlalu spesifik untuk ditempatkan di kelas tujuan umum. Misalnya, IsValidIBAN(this string input)akan terlalu spesifik untuk memilikinya pada string.
Squirrelkiller

3

Jika Anda menginginkan metode sederhana untuk menyelesaikan masalah ini. (Dapat digunakan sebagai ekstensi)

Lihat di bawah:

    public static string RemoveFirstInstanceOfString(this string value, string removeString)
    {
        int index = value.IndexOf(removeString, StringComparison.Ordinal);
        return index < 0 ? value : value.Remove(index, removeString.Length);
    }

Pemakaian:

    string valueWithPipes = "| 1 | 2 | 3";
    string valueWithoutFirstpipe = valueWithPipes.RemoveFirstInstanceOfString("|");
    //Output, valueWithoutFirstpipe = " 1 | 2 | 3";

Terinspirasi oleh dan memodifikasi jawaban @ LukeH dan @ Mike.

Jangan lupa StringComparison.Ordinal untuk mencegah masalah dengan pengaturan Budaya. https://www.jetbrains.com/help/resharper/2018.2/StringIndexOfIsCultureSpecific.1.html


2

Saya sangat setuju bahwa ini sempurna untuk metode penyuluhan, tetapi menurut saya ini dapat sedikit ditingkatkan.

public static string Remove(this string source, string remove,  int firstN)
    {
        if(firstN <= 0 || string.IsNullOrEmpty(source) || string.IsNullOrEmpty(remove))
        {
            return source;
        }
        int index = source.IndexOf(remove);
        return index < 0 ? source : source.Remove(index, remove.Length).Remove(remove, --firstN);
    }

Ini melakukan sedikit rekursi yang selalu menyenangkan.

Berikut ini tes unit sederhana juga:

   [TestMethod()]
    public void RemoveTwiceTest()
    {
        string source = "look up look up look it up";
        string remove = "look";
        int firstN = 2;
        string expected = " up  up look it up";
        string actual;
        actual = source.Remove(remove, firstN);
        Assert.AreEqual(expected, actual);

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