Мы занимаемся интеграцией связи с внешним API. До сих пор это было немного головной болью из-за непоследовательного именования, плохой документации и ненадежных ответов/сообщений об ошибках.
Одна из вещей, с которой мы имеем дело, заключается в том, что определенные запросы, которые мы им отправляем, имеют ограничения на длину строк. Ничего новаторского, кроме любого запроса, который содержит любую строку, превышающую требования по длине, просто отклоняется и терпит неудачу.
Наше решение состояло в том, чтобы создать метод расширения для строки, который просто принимает максимальную длину и возвращает подстроку этой длины, начиная с индекса 0.
Я младший разработчик, и это моя первая работа, поэтому я знаю, что мои решения, возможно, не самые элегантные или эффективные. В любом случае, я указал на то, что с нашим текущим расширением мы могли бы в конечном итоге удалить соответствующую информацию, включив потенциально бесполезные пробелы, поскольку мы не обрезаем и не делаем ничего для проверки на наличие двойных пробелов и т. д. Мой руководитель сказал мне, что я могу не стесняться делать перегрузка расширения, которое позволит вам также выбрать удаление пробелов.
Я придумал 3 решения, которые полностью удаляют любые двойные пробелы. Я знаю, что метод 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"
как-тоTheQuickestResult (метод 1): 12840 тактов
regexResult (метод 2): 14889 тактов
stringBuilderResult (метод 3): 15798 тактов
static readonly
экземпляр с обязательным флаги. Для построителя строк вы, вероятно, захотите передатьmaxLength
какcapacity
. - person GSerg   schedule 28.07.2016stringToShorten?.Length < maxLength
будетfalse
,string.IsNullOrWhiteSpace(stringToShorten)
будетtrue
,false || true
будетtrue
. - person GSerg   schedule 28.07.2016