C#-別の文字列から部分文字列の最初の出現を削除する最も簡単な方法


87

文字列の最初の(そして最初の)出現を別の文字列から削除する必要があります。

文字列を置き換える例を次に示します"\\Iteration"。この:

ProjectName \\ Iteration \\ Release1 \\ Iteration1

これになります:

ProjectName \\ Release1 \\ Iteration1

これを行ういくつかのコードは次のとおりです。

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;

それはたくさんのコードのようです。

だから私の質問はこれです:これを行うためのよりクリーンな/より読みやすい/より簡潔な方法はありますか?

回答:


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

10
この答えは、非ASCII文字を含む文字列では壊れることがあります。たとえば、en-US文化ではæaeは等しいと見なされます。削除しようpaediaとするとEncyclopædiaスローされますArgumentOutOfRangeException、あなたが6つの文字を削除しようとしているだけなので、サブストリングマッチングが5含まれている場合、
ダグラス

6
sourceString.IndexOf(removeString, StringComparison.Ordinal)例外を回避するために、次のように変更できます。
ボリスラフ・イワノフ

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

編集:@OregonGhostは正しいです。私自身も条件文でスクリプトを分割してそのようなことが発生していないか確認していましたが、何らかの要件で文字列が互いに属するように指定されていることを前提に操作していました。ビジネスで必要な例外処理ルールがこの可能性を捕らえることが期待される可能性があります。私自身は、条件付きチェックを実行するために、またそれを十分に読むのに時間がかからないかもしれないジュニア開発者のためにそれをもう少し読みやすくするために、いくつかの余分な行を使用します。


9
removeStringがsourceStringに含まれていない場合、これはクラッシュします。
OregonGhost 2010

26
sourceString.Replace(removeString, "");

18
String.Replaceは、「[r]現在のインスタンスで指定された文字列のすべての出現箇所が別の指定された文字列に置き換えられる新しい文字列を返します」と述べています。OPは最初のオカレンスを置き換えたいと考えていました。
ワイハリー

6
また、コードのみの回答は受け入れられないため、回答について少し説明する必要があります。他の答えを見て、いくつかのヒントについてあなたの答えと比較してください。
ワイハリー

11

このための簡単なTDDテストを作成しました

    [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(input、 ""、1); 「」を使用して、パターンに一致するものを1回入力で検索するように指示します。


2
そのようにあなたは問題を解決しました。このような問題に正規表現を使用する場合は、パフォーマンスを考慮してください。
トーマス

7

あなたは楽しみのために拡張メソッドを使うことができます。通常、文字列のような汎用クラスに拡張メソッドをアタッチすることはお勧めしませんが、私が言ったように、これは楽しいことです。車輪の再発明に意味がないので、@ Lukeの答えを借りました。

[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
Stringのような汎用クラスに拡張メソッドをアタッチすることを通常推奨しないのはなぜですか?これにはどのような明らかな欠点がありますか?
Teun Kooijman 2017年

1
そのような汎用クラスにそれを持たせるにはあまりにも特定の目的のために拡張メソッドを構築するのは簡単です。たとえば、IsValidIBAN(this string input)文字列に含めるには具体的すぎます。
Squirrelkiller

3

この問題を解決する簡単な方法が必要な場合。(拡張機能として使用できます)

下記参照:

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

使用法:

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

@LukeHと@Mikeの回答に触発され、修正されました。

カルチャ設定の問題を防ぐために、StringComparison.Ordinalを忘れないでください。 https://www.jetbrains.com/help/resharper/2018.2/StringIndexOfIsCultureSpecific.1.html


2

これは拡張メソッドに最適であることに間違いなく同意しますが、少し改善できると思います。

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

これは、常に楽しい少しの再帰を行います。

これも簡単な単体テストです。

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

    }
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.