我正在调用一个REST API,并收到一个XML响应。它返回一个工作区名称列表,我正在编写一个快速的IsExistingWorkspace()方法。因为所有的工作空间都是由没有空格的连续字符组成的,我假设找出特定工作空间是否在列表中最简单的方法是删除所有空格(包括换行符)并这样做(XML是从web请求接收到的字符串):
XML.Contains("<name>" + workspaceName + "</name>");
我知道这是区分大小写的,我就靠这一点了。我只是需要一种方法来有效地删除字符串中的所有空白。我知道RegEx和LINQ可以做到,但我对其他想法持开放态度。我最关心的是速度。
这是我所知道的最快的方法,即使你说你不想使用正则表达式:
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);
}
这是我所知道的最快的方法,即使你说你不想使用正则表达式:
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);
}
我发现不同的结果是正确的。我试图用一个空格替换所有空白,正则表达式非常慢。
return( Regex::Replace( text, L"\s+", L" " ) );
对我来说(在c++ cli中)最有效的方法是:
String^ ReduceWhitespace( String^ text )
{
String^ newText;
bool inWhitespace = false;
Int32 posStart = 0;
Int32 pos = 0;
for( pos = 0; pos < text->Length; ++pos )
{
wchar_t cc = text[pos];
if( Char::IsWhiteSpace( cc ) )
{
if( !inWhitespace )
{
if( pos > posStart ) newText += text->Substring( posStart, pos - posStart );
inWhitespace = true;
newText += L' ';
}
posStart = pos + 1;
}
else
{
if( inWhitespace )
{
inWhitespace = false;
posStart = pos;
}
}
}
if( pos > posStart ) newText += text->Substring( posStart, pos - posStart );
return( newText );
}
我首先尝试了上面的例程,分别替换每个字符,但不得不切换到为非空格部分执行子字符串。当应用到1,200,000字符的字符串时:
上面的程序可以在25秒内完成
上面的程序+单独的字符替换在95秒内
正则表达式在15分钟后中止。
我在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%。另外,对于我修改的那个,我使用了这个技巧。