我正在调用一个REST API,并收到一个XML响应。它返回一个工作区名称列表,我正在编写一个快速的IsExistingWorkspace()方法。因为所有的工作空间都是由没有空格的连续字符组成的,我假设找出特定工作空间是否在列表中最简单的方法是删除所有空格(包括换行符)并这样做(XML是从web请求接收到的字符串):

XML.Contains("<name>" + workspaceName + "</name>");

我知道这是区分大小写的,我就靠这一点了。我只是需要一种方法来有效地删除字符串中的所有空白。我知道RegEx和LINQ可以做到,但我对其他想法持开放态度。我最关心的是速度。


当前回答

我在CodeProject上找到了一篇由Felipe Machado(在Richard Robertson的帮助下)撰写的关于这方面的不错的文章。

他测试了十种不同的方法。这是最快安全的版本…

public static string TrimAllWithInplaceCharArray(string str) {

    var len = str.Length;
    var src = str.ToCharArray();
    int dstIdx = 0;

    for (int i = 0; i < len; i++) {
        var ch = src[i];

        switch (ch) {

            case '\u0020': case '\u00A0': case '\u1680': case '\u2000': case '\u2001':

            case '\u2002': case '\u2003': case '\u2004': case '\u2005': case '\u2006':

            case '\u2007': case '\u2008': case '\u2009': case '\u200A': case '\u202F':

            case '\u205F': case '\u3000': case '\u2028': case '\u2029': case '\u0009':

            case '\u000A': case '\u000B': case '\u000C': case '\u000D': case '\u0085':
                continue;

            default:
                src[dstIdx++] = ch;
                break;
        }
    }
    return new string(src, 0, dstIdx);
}

最快的不安全版本…(Sunsetquest 2021年5月26日的一些改进)

public static unsafe void RemoveAllWhitespace(ref string str)
{
    fixed (char* pfixed = str)
    {
        char* dst = pfixed;
        for (char* p = pfixed; *p != 0; p++)
        {
            switch (*p)
            {
                case '\u0020': case '\u00A0': case '\u1680': case '\u2000': case '\u2001':
                case '\u2002': case '\u2003': case '\u2004': case '\u2005': case '\u2006':
                case '\u2007': case '\u2008': case '\u2009': case '\u200A': case '\u202F':
                case '\u205F': case '\u3000': case '\u2028': case '\u2029': case '\u0009':
                case '\u000A': case '\u000B': case '\u000C': case '\u000D': case '\u0085':
                continue;

                default:
                    *dst++ = *p;
                    break;
            }
        }

        uint* pi = (uint*)pfixed;
        ulong len = ((ulong)dst - (ulong)pfixed) >> 1;
        pi[-1] = (uint)len;
        pfixed[len] = '\0';
    }
}

在Stack Overflow上也有一些由Stian Standahl编写的独立基准测试,它们也显示了Felipe的函数比第二快的函数快300%。另外,对于我修改的那个,我使用了这个技巧。

其他回答

这是我所知道的最快的方法,即使你说你不想使用正则表达式:

Regex.Replace(XML, @"\s+", "");

如果您计划多次这样做,请在评论中注明@ hyperhuman,创建并存储一个Regex实例。这将节省每次构建它的开销,这比您想象的要昂贵得多。

private static readonly Regex sWhitespace = new Regex(@"\s+");
public static string ReplaceWhitespace(string input, string replacement) 
{
    return sWhitespace.Replace(input, replacement);
}

如果需要出色的性能,在这种情况下应该避免使用LINQ和正则表达式。我做了一些性能基准测试,似乎如果你想从字符串的开头和结尾去除空白,string. trim()是你的最终函数。

如果你需要从字符串中去除所有的空格,下面的方法是最快的:

    public static string RemoveWhitespace(this string input)
    {
        int j = 0, inputlen = input.Length;
        char[] newarr = new char[inputlen];

        for (int i = 0; i < inputlen; ++i)
        {
            char tmp = input[i];

            if (!char.IsWhiteSpace(tmp))
            {
                newarr[j] = tmp;
                ++j;
            }
        }
        return new String(newarr, 0, j);
    }

我假设您的XML响应如下所示:

var xml = @"<names>
                <name>
                    foo
                </name>
                <name>
                    bar
                </name>
            </names>";

处理XML的最佳方法是使用XML解析器,例如LINQ to XML:

var doc = XDocument.Parse(xml);

var containsFoo = doc.Root
                     .Elements("name")
                     .Any(e => ((string)e).Trim() == "foo");

使用Linq,你可以这样写一个可读的方法:

    public static string RemoveAllWhitespaces(this string source)
    {
        return string.IsNullOrEmpty(source) ? source : new string(source.Where(x => !char.IsWhiteSpace(x)).ToArray());
    }

我们可以用:

    public static string RemoveWhitespace(this string input)
    {
        if (input == null)
            return null;
        return new string(input.ToCharArray()
            .Where(c => !Char.IsWhiteSpace(c))
            .ToArray());
    }