(РЕДАКТИРОВАТЬ: см. Внизу поста для тестов по различным микро-оптимизации метода)
Не обрезайте его - это может создать новую строку, которая вам на самом деле не нужна. Вместо этого просмотрите строку для любых символов, которые не являются пробелами (для любого определения, которое вы хотите). Например:
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
может быть столь же эффективным, как этот. Кажется, что 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 делает здесь интересные вещи с точки зрения удаления повторяющихся проверок границ и т. Д.
Код: (см. мою запись в блоге по бенчмаркингу для фреймворка, против которого она написана)
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