.NET StringBuilder - 检查是否以字符串结尾

Ale*_* Dn 13 .net c# string stringbuilder

检查是否StringBuilder以特定字符串结束的最佳(最短和最快)方法是什么?

如果我只想检查一个字符,这不是问题sb[sb.Length-1] == 'c',但如何检查它是否以更长的字符串结尾?

我可以考虑像循环"some string".Length和逐个读取字符之类的东西,但也许存在更简单的东西?:)

最后我想要像这样的扩展方法:

StringBuilder sb = new StringBuilder("Hello world");
bool hasString = sb.EndsWith("world");
Run Code Online (Sandbox Code Playgroud)

Dou*_*las 24

要避免生成完整字符串的性能开销,可以使用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);
}
Run Code Online (Sandbox Code Playgroud)

编辑:可能需要定义一个带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);
}
Run Code Online (Sandbox Code Playgroud)

编辑2:正如Tim S在评论中指出的那样,我的答案中存在一个缺陷(以及所有其他假设基于字符的相等的答案),这些缺陷会影响某些Unicode比较.Unicode不要求两个(子)字符串具有相同的字符序列.例如,预先组合的字符é应被视为等于e组合标记后面的字符U+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
Run Code Online (Sandbox Code Playgroud)

如果要正确处理这些情况,最简单的方法是调用StringBuilder.ToString(),然后使用内置函数String.EndsWith.

  • 在某些文化比较中,这是行不通的.例如来自http://msdn.microsoft.com/en-us/library/t9h2fbth.aspx的示例,使用StringBuilder都返回`False`.见http://ideone.com/mVHhWR (3认同)

Hem*_*rio 6

在 msdn 上,您可以找到有关如何在 StringBuilder 对象中搜索文本的主题。您可以使用的两个选项是:

  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;
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 我也想避免 `ToString()` 但是:for 循环有最好的情况和最坏的情况。在**最坏的情况**(最后测试的字符不同)for 循环慢 7 倍,在**最佳情况**(第一个字符测试不同)它向后快 77 甚至向前快 140 倍(取决于循环方向) . 我测试了发布版本,每个方法版本调用 1m 次,测试字符串长度为 1000。 (2认同)