Проверяете содержимое строки?Длина строки против пустой строки

StackOverflow https://stackoverflow.com/questions/10230

Вопрос

Что более эффективно для компилятора и как лучше всего проверять, является ли строка пустой?

  1. Проверка того, равна ли длина строки == 0
  2. Проверка того, пуста ли строка (strVar == "")

Кроме того, зависит ли ответ от языка?

Это было полезно?

Решение

Да, это зависит от языка, поскольку хранение строк в разных языках различается.

  • Строки типа Паскаль: Length = 0.
  • Строки в стиле C: [0] == 0.
  • .СЕТЬ: .IsNullOrEmpty.

И т. д.

Другие советы

В языках, использующих строки в стиле C (с нулевым завершением), по сравнению с "" будет быстрее.Это операция O(1), а длина строки в стиле C равна O(n).

В языках, которые хранят длину как часть строкового объекта (C#, Java,...), проверка длины также осуществляется за O(1).В этом случае непосредственная проверка длины выполняется быстрее, поскольку позволяет избежать накладных расходов на создание новой пустой строки.

В .Net:

string.IsNullOrEmpty( nystr );

строки могут быть нулевыми, поэтому .Length иногда выдает исключение NullReferenceException

В языках, использующих строки в стиле C (с нулевым завершением), сравнение с "" будет быстрее.

На самом деле, возможно, лучше проверить, является ли первый символ в строке '\0':

char *mystring;
/* do something with the string */
if ((mystring != NULL) && (mystring[0] == '\0')) {
    /* the string is empty */
}

В Perl есть третий вариант: строка не определена.Это немного отличается от NULL-указателя в C, хотя бы потому, что вы не получаете ошибку сегментации при доступе к неопределенной строке.

В Java 1.6 у класса String появился новый метод. пусто

Существует также общественная библиотека Джакарты, в которой имеется isBlank метод.Пустой определяется как строка, содержащая только пробелы.

Предполагая, что ваш вопрос .NET:

Если вы хотите проверить свою строку на нулевое значение, используйте IsNullOrEmpty. Если вы уже знаете, что ваша строка не равна нулю, например, при проверке TextBox.Text и т. д., не используйте IsNullOrEmpty, а затем возникает ваш вопрос.
Так что, на мой взгляд, String.Length менее производительен, чем сравнение строк.

Я проверил это (я также тестировал на C#, тот же результат):

Module Module1
  Sub Main()
    Dim myString = ""


    Dim a, b, c, d As Long

    Console.WriteLine("Way 1...")

    a = Now.Ticks
    For index = 0 To 10000000
      Dim isEmpty = myString = ""
    Next
    b = Now.Ticks

    Console.WriteLine("Way 2...")

    c = Now.Ticks
    For index = 0 To 10000000
      Dim isEmpty = myString.Length = 0
    Next
    d = Now.Ticks

    Dim way1 = b - a, way2 = d - c

    Console.WriteLine("way 1 took {0} ticks", way1)
    Console.WriteLine("way 2 took {0} ticks", way2)
    Console.WriteLine("way 1 took {0} ticks more than way 2", way1 - way2)
    Console.Read()
  End Sub
End Module

Результат:

Way 1...
Way 2...
way 1 took 624001 ticks
way 2 took 468001 ticks
way 1 took 156000 ticks more than way 2

Это означает, что сравнение требует гораздо большего, чем проверка длины строки.

String.IsNullOrEmpty() работает только в .net 2.0 и выше, для .net 1/1.1 я обычно использую:

if (inputString == null || inputString == String.Empty)
{
    // String is null or empty, do something clever here. Or just expload.
}

Я использую String.Empty вместо "", потому что "" создаст объект, тогда как String.Empty не будет - я знаю, что это что-то маленькое и тривиальное, но я все равно предпочитаю не создавать объекты, когда они мне не нужны!(Источник)

На самом деле, по моему мнению, лучший способ определить это — метод IsNullOrEmpty() строкового класса.

http://msdn.microsoft.com/en-us/library/system.string.isnullorempty.

Обновлять:Я предполагал, что .Net, на других языках все может быть по-другому.

В этом случае непосредственная проверка длины выполняется быстрее, поскольку позволяет избежать накладных расходов на создание новой пустой строки.

@ДерекПарк:Это не всегда так.«» — это строковый литерал, поэтому в Java он почти наверняка уже интернирован.

Для строк C,

if (s[0] == 0)

будет быстрее, чем любой

if (strlen(s) == 0)

или

if (strcmp(s, "") == 0)

потому что вы избежите накладных расходов на вызов функции.

@Натан

На самом деле, возможно, лучше проверить, является ли первый символ в строке '\0':

Я почти упомянул об этом, но в итоге пропустил это, поскольку звонил strcmp() с пустой строкой и непосредственная проверка первого символа в строке - это O (1).По сути, вы просто платите за дополнительный вызов функции, что довольно дешево.Если вы Действительно тем не менее, вам нужна абсолютно лучшая скорость, обязательно используйте прямое сравнение первого символа с 0.

Честно говоря, я всегда использую strlen() == 0, потому что у меня есть никогда написал программу, в которой на самом деле это была измеримая проблема с производительностью, и я думаю, что это наиболее понятный способ выразить проверку.

Опять же, не зная языка, сказать невозможно.

Тем не менее, я рекомендую вам выбрать метод, который будет наиболее понятен программисту по сопровождению, который будет сопровождать вашу работу.

Я бы рекомендовал написать функцию, которая явно делает то, что вы хотите, например

#define IS_EMPTY(s) ((s)[0]==0)

или сопоставимый.Теперь нет никаких сомнений в том, что вы проверяете.

Прочитав эту ветку, я провел небольшой эксперимент, который дал два разных и интересных вывода.

Рассмотрим следующее.

strInstallString    "1" string

Вышеупомянутое скопировано из окна локальных настроек отладчика Visual Studio.Одно и то же значение используется во всех трех следующих примерах.

if ( strInstallString == "" ) === if ( strInstallString == string.Empty )

Ниже приведен код, отображаемый в окне дизассемблирования отладчика Visual Studio 2013 для этих двух принципиально идентичных случаев.

if ( strInstallString == "" )
003126FB  mov         edx,dword ptr ds:[31B2184h]
00312701  mov         ecx,dword ptr [ebp-50h]
00312704  call        59DEC0B0            ; On return, EAX = 0x00000000.
00312709  mov         dword ptr [ebp-9Ch],eax
0031270F  cmp         dword ptr [ebp-9Ch],0
00312716  sete        al
00312719  movzx       eax,al
0031271C  mov         dword ptr [ebp-64h],eax
0031271F  cmp         dword ptr [ebp-64h],0
00312723  jne         00312750

if ( strInstallString == string.Empty )
00452443  mov         edx,dword ptr ds:[3282184h]
00452449  mov         ecx,dword ptr [ebp-50h]
0045244C  call        59DEC0B0        ; On return, EAX = 0x00000000.
00452451  mov         dword ptr [ebp-9Ch],eax
00452457  cmp         dword ptr [ebp-9Ch],0
0045245E  sete        al
00452461  movzx       eax,al
00452464  mov         dword ptr [ebp-64h],eax
00452467  cmp         dword ptr [ebp-64h],0
0045246B  jne         00452498

if ( strInstallString == string.Empty ) существенно не отличается

if ( strInstallString.Length == 0 )
003E284B  mov         ecx,dword ptr [ebp-50h]
003E284E  cmp         dword ptr [ecx],ecx
003E2850  call        5ACBC87E        ; On return, EAX = 0x00000001.
003E2855  mov         dword ptr [ebp-9Ch],eax
003E285B  cmp         dword ptr [ebp-9Ch],0
003E2862  setne       al
003E2865  movzx       eax,al
003E2868  mov         dword ptr [ebp-64h],eax
003E286B  cmp         dword ptr [ebp-64h],0
003E286F  jne         003E289C

Из приведенных выше списков машинного кода, сгенерированных модулем NGEN .NET Framework версии 4.5, я делаю следующие выводы.

  1. Проверка на равенство пустого строкового литерала и статического свойства string.Empty класса System.string для всех практических целей идентична.Единственная разница между двумя фрагментами кода — это источник первой инструкции перемещения, и оба являются смещениями относительно ds, подразумевая, что оба относятся к встроенным константам.

  2. Проверка равенства пустой строки, как литерала, так и свойства string.Empty, устанавливает вызов функции с двумя аргументами, который указывает неравенство вернув ноль.Я основываю этот вывод на других тестах, которые я провел пару месяцев назад, в которых я проследил часть своего собственного кода через границу между управляемым и неуправляемым и обратно.Во всех случаях любой вызов, требующий двух или более аргументов, помещает первый аргумент в регистр ECX, а второй — в регистр EDX.Я не помню, как принимались последующие аргументы.Тем не менее, настройка звонка больше напоминала __fastcall, чем __stdcall.Аналогично, ожидаемые возвращаемые значения всегда отображались в регистре EAX, который практически универсален.

  3. Проверка длины строки вызывает вызов функции с одним аргументом, которая возвращает 1 (в регистре EAX), что соответствует длине проверяемой строки.

  4. Учитывая, что сразу видимый машинный код почти идентичен, единственная причина, которую я могу себе представить, объясняет лучшую производительность равенства строк по длине строки, о которой сообщает Шинни заключается в том, что функция с двумя аргументами, выполняющая сравнение, значительно лучше оптимизирована, чем функция с одним аргументом, которая считывает длину экземпляра строки.

Заключение

В принципе, я избегаю сравнения с пустой строкой как с литералом, потому что литерал пустой строки может показаться неоднозначным в исходном коде.С этой целью мои вспомогательные классы .NET уже давно определили пустую строку как константу.Хотя я использую строка.Пусто для прямых, встроенных сравнений константа используется для определения других констант, значением которых является пустая строка, поскольку константа не может быть присвоена строка.Пусто как его ценность.

Это упражнение раз и навсегда разрешает любые опасения, которые могут возникнуть у меня по поводу стоимости сравнения с любым из них, если таковая имеется. строка.Пусто или константа, определенная моими вспомогательными классами.

Однако возникает также загадочный вопрос о его замене;почему сравнивается с строка.Пусто более эффективно, чем проверка длины строки?Или тест, используемый Шинни, признан недействительным из-за способа реализации цикла?(Мне в это трудно поверить, но, опять же, меня и раньше обманывали, как, я уверен, и вас тоже!)

Я давно это предполагал system.string объекты представляли собой подсчитываемые строки, что в основном похоже на давно устоявшуюся базовую строку (BSTR), которую мы давно знаем из COM.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top