(编辑:有关该方法的不同微优化的基准,请参见帖子底部)
不要修剪它 - 这可能会创建一个您实际上不需要的新字符串。相反,请在字符串中查找任何 不是 空格的字符(对于您想要的任何定义)。例如:
public static bool IsEmptyOrWhitespace(string text)
{
// Avoid creating iterator for trivial case
if (text.Length == 0)
{
return true;
}
foreach (char c in text)
{
// Could use Char.IsWhiteSpace(c) instead
if (c==' ' || c=='\t' || c=='\r' || c=='\n')
{
continue;
}
return false;
}
return true;
}
如果text 是null,您还可以考虑您希望该方法做什么。
可能进行进一步的微优化实验:
-
foreach 比使用下面的 for 循环快还是慢?请注意,使用for 循环,您可以在开始时删除“if (text.Length==0)”测试。
for (int i = 0; i < text.Length; i++)
{
char c = text[i];
// ...
-
与上面相同,但提升了Length 调用。请注意,这 不适用于普通数组,但 可能 对字符串有用。我没有测试过。
int length = text.Length;
for (int i = 0; i < length; i++)
{
char c = text[i];
-
在循环体中,我们得到的和:
if (c != ' ' && c != '\t' && c != '\r' && c != '\n')
{
return false;
}
-
开关/机箱会更快吗?
switch (c)
{
case ' ': case '\r': case '\n': case '\t':
return false;
}
修剪行为更新
我一直在研究Trim 如何能像这样高效。似乎Trim 只会在需要时创建一个新字符串。如果它可以返回this 或"",它将:
using System;
class Test
{
static void Main()
{
CheckTrim(string.Copy(""));
CheckTrim(" ");
CheckTrim(" x ");
CheckTrim("xx");
}
static void CheckTrim(string text)
{
string trimmed = text.Trim();
Console.WriteLine ("Text: '{0}'", text);
Console.WriteLine ("Trimmed ref == text? {0}",
object.ReferenceEquals(text, trimmed));
Console.WriteLine ("Trimmed ref == \"\"? {0}",
object.ReferenceEquals("", trimmed));
Console.WriteLine();
}
}
这意味着这个问题中的任何基准测试都应该使用混合数据,这一点非常重要:
当然,这四者之间的“现实世界”平衡是无法预测的……
基准测试
我已经对原始建议与我的建议进行了一些基准测试,而且我的似乎在我投入的所有内容中都获胜,考虑到其他答案的结果,这让我感到惊讶。但是,我还对 foreach、for 使用 text.Length、for 使用 text.Length 一次然后反转迭代顺序以及 for 与提升长度之间的差异进行了基准测试。
基本上for 循环稍微快一点,但提升长度检查使其比foreach 慢。反转for 循环方向也比foreach 慢得多。我强烈怀疑 JIT 在这里做了一些有趣的事情,比如删除重复的边界检查等。
代码:(请参阅 my benchmarking blog entry 了解此框架所针对的编写)
using System;
using BenchmarkHelper;
public class TrimStrings
{
static void Main()
{
Test("");
Test(" ");
Test(" x ");
Test("x");
Test(new string('x', 1000));
Test(" " + new string('x', 1000) + " ");
Test(new string(' ', 1000));
}
static void Test(string text)
{
bool expectedResult = text.Trim().Length == 0;
string title = string.Format("Length={0}, result={1}", text.Length,
expectedResult);
var results = TestSuite.Create(title, text, expectedResult)
/* .Add(x => x.Trim().Length == 0, "Trim().Length == 0")
.Add(x => x.Trim() == "", "Trim() == \"\"")
.Add(x => x.Trim().Equals(""), "Trim().Equals(\"\")")
.Add(x => x.Trim() == string.Empty, "Trim() == string.Empty")
.Add(x => x.Trim().Equals(string.Empty), "Trim().Equals(string.Empty)")
*/
.Add(OriginalIsEmptyOrWhitespace)
.Add(IsEmptyOrWhitespaceForLoop)
.Add(IsEmptyOrWhitespaceForLoopReversed)
.Add(IsEmptyOrWhitespaceForLoopHoistedLength)
.RunTests()
.ScaleByBest(ScalingMode.VaryDuration);
results.Display(ResultColumns.NameAndDuration | ResultColumns.Score,
results.FindBest());
}
public static bool OriginalIsEmptyOrWhitespace(string text)
{
if (text.Length == 0)
{
return true;
}
foreach (char c in text)
{
if (c==' ' || c=='\t' || c=='\r' || c=='\n')
{
continue;
}
return false;
}
return true;
}
public static bool IsEmptyOrWhitespaceForLoop(string text)
{
for (int i=0; i < text.Length; i++)
{
char c = text[i];
if (c==' ' || c=='\t' || c=='\r' || c=='\n')
{
continue;
}
return false;
}
return true;
}
public static bool IsEmptyOrWhitespaceForLoopReversed(string text)
{
for (int i=text.Length-1; i >= 0; i--)
{
char c = text[i];
if (c==' ' || c=='\t' || c=='\r' || c=='\n')
{
continue;
}
return false;
}
return true;
}
public static bool IsEmptyOrWhitespaceForLoopHoistedLength(string text)
{
int length = text.Length;
for (int i=0; i < length; i++)
{
char c = text[i];
if (c==' ' || c=='\t' || c=='\r' || c=='\n')
{
continue;
}
return false;
}
return true;
}
}
结果:
============ Length=0, result=True ============
OriginalIsEmptyOrWhitespace 30.012 1.00
IsEmptyOrWhitespaceForLoop 30.802 1.03
IsEmptyOrWhitespaceForLoopReversed 32.944 1.10
IsEmptyOrWhitespaceForLoopHoistedLength 35.113 1.17
============ Length=1, result=True ============
OriginalIsEmptyOrWhitespace 31.150 1.04
IsEmptyOrWhitespaceForLoop 30.051 1.00
IsEmptyOrWhitespaceForLoopReversed 31.602 1.05
IsEmptyOrWhitespaceForLoopHoistedLength 33.383 1.11
============ Length=3, result=False ============
OriginalIsEmptyOrWhitespace 30.221 1.00
IsEmptyOrWhitespaceForLoop 30.131 1.00
IsEmptyOrWhitespaceForLoopReversed 34.502 1.15
IsEmptyOrWhitespaceForLoopHoistedLength 35.690 1.18
============ Length=1, result=False ============
OriginalIsEmptyOrWhitespace 31.626 1.05
IsEmptyOrWhitespaceForLoop 30.005 1.00
IsEmptyOrWhitespaceForLoopReversed 32.383 1.08
IsEmptyOrWhitespaceForLoopHoistedLength 33.666 1.12
============ Length=1000, result=False ============
OriginalIsEmptyOrWhitespace 30.177 1.00
IsEmptyOrWhitespaceForLoop 33.207 1.10
IsEmptyOrWhitespaceForLoopReversed 30.867 1.02
IsEmptyOrWhitespaceForLoopHoistedLength 31.837 1.06
============ Length=1002, result=False ============
OriginalIsEmptyOrWhitespace 30.217 1.01
IsEmptyOrWhitespaceForLoop 30.026 1.00
IsEmptyOrWhitespaceForLoopReversed 34.162 1.14
IsEmptyOrWhitespaceForLoopHoistedLength 34.860 1.16
============ Length=1000, result=True ============
OriginalIsEmptyOrWhitespace 30.303 1.01
IsEmptyOrWhitespaceForLoop 30.018 1.00
IsEmptyOrWhitespaceForLoopReversed 35.475 1.18
IsEmptyOrWhitespaceForLoopHoistedLength 40.927 1.36