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?

Vaccano
sumber

Jawaban:

155
int index = sourceString.IndexOf(removeString);
string cleanPath = (index < 0)
    ? sourceString
    : sourceString.Remove(index, removeString.Length);
LukeH
sumber
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.

Joel Etherton
sumber
9
Ini akan macet jika removeString tidak terdapat dalam sourceString.
OregonGhost
27
sourceString.Replace(removeString, "");
malcolm waldron.dll
sumber
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.

CaffGeek
sumber
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);
    }
}
Mike Valenty
sumber
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

Daniel Filipe
sumber
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);

    }
Greg Roberts
sumber