【发布时间】:2016-12-02 22:20:29
【问题描述】:
我们正在处理与外部 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 foo bar foobar”
somehowTheQuickestResult(方法 1):12840 滴答声
regexResult(方法 2):14889 个滴答声
stringBuilderResult(方法 3):15798 个滴答声
【问题讨论】:
-
如果您使用字符数组并将非空白字符移到上面可能会更快。对于更大的字符串比较,您当前的方法可能会得到非常不同的结果跨度>
-
附带说明,所有方法都将返回一个包含大量空格的字符串,即使它太长。
-
@GSerg 不确定您的第一条评论是什么意思?如果字符串比 maxLength 短,那么我只返回它,因为在这种情况下,我不关心删除空格。删除空格的目的是在字符串超过 maxLength 时允许尽可能多的相关信息与请求一起传递。因此,我认为每种方法的第一行和最后一行都解决了您指出的问题。至于您的第二条评论,感谢您提供的信息,我将研究这两个选项并检查结果!
-
@WRP 如果您传递一个包含一千个空格且仅包含其他内容的字符串,它将原封不动地返回。
stringToShorten?.Length < maxLength将是false,string.IsNullOrWhiteSpace(stringToShorten)将是true,false || true是true。
标签: c# regex replace stringbuilder removing-whitespace