[英]Why is Regex and StringBuilder slower at removing white space?
我們正在與外部API集成通信。 到目前為止,由於命名不一致,文檔不正確以及響應/錯誤消息不可靠,這讓人有些頭疼。
我們正在處理的事情之一是,我們發送給他們的某些請求對字符串的長度有限制。 沒有任何突破性的要求,但是任何包含任何超出長度要求的字符串的請求都將被拒絕並失敗。
我們的解決方案是為字符串創建一個擴展方法,該方法只采用最大長度,並返回從索引0開始的該長度的子字符串。
我是一名初級開發人員,這是我的第一份工作,所以我知道我的解決方案很可能不是最優雅或最有效的。 無論哪種方式,我都提出了一個要點,即由於我們當前的擴展名,我們可能最終會刪除相關的信息,同時包括可能毫無用處的空白,因為我們沒有進行修剪或做任何檢查雙倍空格的操作。等等。我的領導告訴我,隨時可以擴展名超載,您也可以選擇刪除空白。
我想出了3種解決方案,它們可以完全消除任何雙空格。 我知道Regex方法是唯一真正刪除所有空白的方法,而另兩個方法則是將所有出現的兩個空白都排回。 但是,此站點將僅在美國使用,因此我不確定是否需要額外花費Regex。
我發布此文章的主要興趣是,我想知道是否有人可以解釋為什么我使用StringBuilder的方法與其他兩個方法相比效率如此之低,甚至比Regex還要慢,我希望它是這三個方法中最快的。 這里的任何見解都受到贊賞,並暗示了比我提出的任何方法更好的方法。
這是我的三個擴展:
public static string SafeSubstringSomehowTheQuickest(this string stringToShorten, int maxLength)
{
if (stringToShorten?.Length < maxLength || string.IsNullOrWhiteSpace(stringToShorten)) return stringToShorten;
stringToShorten = stringToShorten.Trim();
int stringOriginalLength = stringToShorten.Length;
int extraWhitespaceCount = 0;
for (int i = 0; i < stringOriginalLength - extraWhitespaceCount; i++)
{
int stringLengthBeforeReplace = stringToShorten.Length;
stringToShorten = stringToShorten.Replace(" ", " ");
if(stringLengthBeforeReplace < stringToShorten.Length) { extraWhitespaceCount += stringToShorten.Length - stringLengthBeforeReplace; }
}
return stringToShorten.Length > maxLength ? stringToShorten.Substring(0, maxLength) : stringToShorten;
}
public static string SafeSubstringWithRegex(this string stringToShorten, int maxLength)
{
if (stringToShorten?.Length < maxLength || string.IsNullOrWhiteSpace(stringToShorten)) return stringToShorten;
stringToShorten = System.Text.RegularExpressions.Regex.Replace(stringToShorten, @"\s{2,}", " ").Trim();
return stringToShorten.Length > maxLength ? stringToShorten.Substring(0, maxLength) : stringToShorten;
}
public static string SafeSubstringFromBuilder(this string stringToShorten, int maxLength)
{
if (stringToShorten?.Length < maxLength || string.IsNullOrWhiteSpace(stringToShorten)) return stringToShorten;
StringBuilder bob = new StringBuilder();
bool lastCharWasWhitespace = false;
foreach (char c in stringToShorten)
{
if (c == ' ' && !lastCharWasWhitespace) { bob.Append(c); }
lastCharWasWhitespace = c == ' ';
if (!lastCharWasWhitespace) { bob.Append(c); }
}
stringToShorten = bob.ToString().Trim();
return stringToShorten.Length < maxLength ? stringToShorten : stringToShorten.Substring(0, maxLength);
}
這是我用來比較每個擴展程序運行時間的快速測試:
static void Main(string[] args)
{
var stopwatch = new System.Diagnostics.Stopwatch();
string test =
" foo bar foobar f oo bar foobar foofoo " +
"barbar foo b ar " +
" foo bar foobar f oo bar foobar foofoo " +
"barbar foo b ar " +
" foo bar foobar f oo bar foobar foofoo " +
"barbar foo b ar " +
" foo bar foobar f oo bar foobar foofoo " +
"barbar foo b ar " +
" foo bar foobar f oo bar foobar foofoo " +
"barbar foo b ar " +
" foo bar foobar f oo bar foobar foofoo " +
"barbar foo b ar " +
" foo bar foobar f oo bar foobar foofoo " +
"barbar foo b ar " +
" foo bar foobar f oo bar foobar foofoo " +
"barbar foo b ar " +
" foo bar foobar f oo bar foobar foofoo " +
"barbar foo b ar " +
" foo bar foobar f oo bar foobar foofoo " +
"barbar foo b ar " +
" foo bar foobar f oo bar foobar foofoo " +
"barbar foo b ar " +
" foo bar foobar f oo bar foobar foofoo " +
"barbar foo b ar " +
" foo bar foobar f oo bar foobar foofoo " +
"barbar foo b ar ";
int stringStartingLength = test.Length;
int stringMaxLength = 30;
stopwatch.Start();
string somehowTheQuickestResult = test.SafeSubstringSomehowTheQuickest(stringMaxLength);
stopwatch.Stop();
var somehowTheQuickestResultTicks = stopwatch.ElapsedTicks;
stopwatch.Start();
string regexResult = test.SafeSubstringWithRegex(stringMaxLength);
stopwatch.Stop();
var regexResultTicks = stopwatch.ElapsedTicks;
stopwatch.Start();
string stringBuilderResult = test.SafeSubstringFromBuilder(stringMaxLength);
stopwatch.Stop();
var stringBuilderResultTicks = stopwatch.ElapsedTicks;
}
最終,這些是結果,每次運行的滴答滴答都有所不同,但是這三種方法之間的差異是相當一致的:
這三個都返回相同的字符串:“ foo bar foobar f oo bar foobar”
SomehowTheQuickestResult(method 1):12840 ticks
regexResult(方法2): 14889次
stringBuilderResult(方法3): 15798次
您在進行基准測試時有些錯誤。
首先,您需要“熱身”並讓JIT做好工作。 基本上,只需調用您的三個方法並丟棄結果即可。
其次,單次嘗試不具有代表性。 嘗試超過100次或更多次迭代的平均時間(或中值時間)。
第三,您使用Stopwatch
是錯誤的。 Stop()
Start()
之后的Start()
恢復間隔測量。 Restart()
是必經之路。 使用它,我的測試顯示以下結果:
9569
314
58
所以, StringBuilder
方法實際上是最快的國家之一。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.