16

StringBuilder特定の文字列で終わるかどうかを確認するための最良の (最短かつ最速の) 方法は何ですか?

1文字だけチェックしたい場合は問題ありませんsb[sb.Length-1] == 'c'が、長い文字列で終わっているかどうかを確認するにはどうすればよいですか?

"some string".Length文字を1文字ずつループして読み込んでいくようなことも考えられるのですが、もっとシンプルなものがあるのではないでしょうか?:)

最後に、次のような拡張メソッドが必要です。

StringBuilder sb = new StringBuilder("Hello world");
bool hasString = sb.EndsWith("world");
4

5 に答える 5

27

完全な文字列を生成するパフォーマンスのオーバーヘッドを回避するためにToString(int,int)、インデックス範囲を取るオーバーロードを使用できます。

public static bool EndsWith(this StringBuilder sb, string test)
{
    if (sb.Length < test.Length)
        return false;

    string end = sb.ToString(sb.Length - test.Length, test.Length);
    return end.Equals(test);
}

編集StringComparison:引数を取るオーバーロードを定義することがおそらく望ましいでしょう:

public static bool EndsWith(this StringBuilder sb, string test)
{
    return EndsWith(sb, test, StringComparison.CurrentCulture);
}

public static bool EndsWith(this StringBuilder sb, string test, 
    StringComparison comparison)
{
    if (sb.Length < test.Length)
        return false;

    string end = sb.ToString(sb.Length - test.Length, test.Length);
    return end.Equals(test, comparison);
}

編集2 : コメントで Tim S が指摘したように、特定の Unicode 比較に影響する私の回答 (および文字ベースの同等性を前提とする他のすべての回答) に欠陥があります。Unicode では、2 つの (サブ) 文字列が同じ文字列であるとみなされる必要はありません。たとえば、構成済みの文字は、結合マークが後に続くé文字と同等に扱われるべきです。eU+0301

Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US");

string s = "We met at the cafe\u0301";
Console.WriteLine(s.EndsWith("café"));    // True 

StringBuilder sb = new StringBuilder(s);
Console.WriteLine(sb.EndsWith("café"));   // False

これらのケースを正しく処理したい場合は、 を呼び出しStringBuilder.ToString()て組み込みの を使用するのが最も簡単かもしれませんString.EndsWith

于 2013-07-10T20:26:11.177 に答える
7

msdnで、StringBuilder オブジェクト内のテキストを検索する方法に関するトピックを見つけることができます。利用可能な 2 つのオプションは次のとおりです。

  1. ToString を呼び出し、返された String オブジェクトを検索します。
  2. Chars プロパティを使用して、文字の範囲を順番に検索します。

最初のオプションは問題外なので。Chars プロパティを使用する必要があります。

public static class StringBuilderExtensions
{
    public static bool EndsWith(this StringBuilder sb, string text)
    {
        if (sb.Length < text.Length)
            return false;

        var sbLength = sb.Length;
        var textLength = text.Length;
        for (int i = 1; i <= textLength; i++)
        {
            if (text[textLength - i] != sb[sbLength - i])
                return false;
        }
        return true;
    }
}
于 2013-07-10T20:42:18.043 に答える
1
    private static bool EndsWith(this StringBuilder builder, string value) {
        return builder.GetLast( value.Length ).SequenceEqual( value );
    }
    private static IEnumerable<char> GetLast(this StringBuilder builder, int count) {
        count = Math.Min( count, builder.Length );
        return Enumerable.Range( builder.Length - count, count ).Select( i => builder[ i ] );
    }
于 2019-09-09T22:40:45.140 に答える
0

私はあなたが要求したものを(あなたが述べた制限付きで)あなたに与えていますが、それを行うための最良の方法ではありません. 何かのようなもの:

StringBuilder sb = new StringBuilder("Hello world"); bool hasString = sb.Remove(1,sb.Length - "world".Length) == "world";

于 2013-07-10T20:35:42.050 に答える