18

コンパイラにとってより効率的で、文字列が空白かどうかをチェックするためのベスト プラクティスはどれですか?

  1. 文字列の長さ == 0 かどうかの確認
  2. 文字列が空かどうかの確認 (strVar == "")

また、答えは言語によって異なりますか?

4

13 に答える 13

18

はい、文字列のストレージは言語によって異なるため、言語によって異なります。

  • Pascal 型の文字列: Length = 0.
  • C スタイルの文字列: [0] == 0.
  • .NET: .IsNullOrEmpty.

等。

于 2008-08-13T19:05:42.357 に答える
17

C スタイル (null で終わる) 文字列を使用する言語では、 との比較""が高速になります。これは O(1) 操作ですが、C スタイルの文字列の長さは O(n) です。

文字列オブジェクトの一部として長さを格納する言語 (C#、Java など) では、長さのチェックも O(1) です。この場合、新しい空の文字列を作成するオーバーヘッドを回避できるため、長さを直接確認する方が高速です。

于 2008-08-13T19:12:19.177 に答える
3

C スタイル (ヌル終了) の文字列を使用する言語では、"" との比較が高速になります。

実際には、文字列の最初の文字が '\0' であるかどうかを確認する方がよい場合があります。

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

Perl には、文字列が未定義であるという 3 番目のオプションがあります。これは、未定義の文字列にアクセスしてもセグメンテーション違反が発生しないという理由だけで、C の NULL ポインターとは少し異なります。

于 2008-08-13T19:52:16.163 に答える
2

.Net では:

string.IsNullOrEmpty( nystr );

文字列は null になる可能性があるため、.Length は NullReferenceException をスローすることがあります

于 2008-08-13T19:05:54.197 に答える
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 はそうではないためです。小さくて些細なことは知っていますが、必要のないオブジェクトは作成しません。(ソース

于 2008-08-14T11:26:53.060 に答える
1

このスレッドを読んだ後、ちょっとした実験を行ったところ、2 つの異なる興味深い結果が得られました。

以下を検討してください。

strInstallString    "1" string

上記は、Visual Studio デバッガーのローカル ウィンドウからコピーされたものです。次の 3 つの例では、すべて同じ値が使用されています。

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

以下は、これら 2 つの基本的に同一のケースについて、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

.NET Framework バージョン 4.5 の NGEN モジュールによって生成された上記のマシン コード リストから、次の結論を導き出します。

  1. 空の文字列リテラルと System.string クラスの static string.Empty プロパティに対する等価性のテストは、実際にはすべて同じです。2 つのコード スニペットの唯一の違いは、最初の move 命令のソースです。どちらも ds に対するオフセットであり、どちらも組み込みの定数を参照していることを意味します。

  2. リテラルまたは string.Empty プロパティのいずれかとして、空の文字列に対して等しいかどうかをテストすると、引数が 2 つの関数呼び出しが設定されます。これは、ゼロを返すことによって不等値を示します。この結論は、数か月前に実行した他のテストに基づいています。このテストでは、マネージド/アンマネージドの境界を越えて独自のコードをたどりました。いずれの場合も、2 つ以上の引数を必要とする呼び出しでは、最初の引数がレジスタ ECX に配置され、2 番目の引数がレジスタ EDX に配置されます。その後の引数がどのように渡されたかは覚えていません。それにもかかわらず、呼び出しセットアップは __stdcall よりも __fastcall に似ていました。同様に、期待される戻り値は常にレジスタ EAX に表示されますが、これはほぼ普遍的です。

  3. 文字列の長さをテストすると、引数が 1 つの関数呼び出しが設定されます。この関数呼び出しは、(レジスタ EAX で) 1 を返します。これは、たまたまテストされている文字列の長さです。

  4. すぐに見える機械語コードがほぼ同じであることを考えると、 Shinnyによって報告された文字列の長さに対する文字列の等価性のより優れたパフォーマンスを説明できる唯一の理由は、比較を実行する 2 つの引数関数が大幅に優れていることです。文字列インスタンスから長さを読み取る引数が 1 つの関数よりも最適化されています。

結論

原則として、空の文字列をリテラルとして比較することは避けています。これは、空の文字列リテラルがソース コード内であいまいに見える可能性があるためです。そのために、私の .NET ヘルパー クラスでは長い間、空の文字列を定数として定義してきました。直接のインライン比較にstring.Emptyを使用していますが、定数には値としてstring.Emptyを割り当てることができないため、定数は、値が空の文字列である他の定数を定義するために保持されます。

この演習では、 string.Emptyまたはヘルパー クラスで定義された定数のいずれかと比較することによるコストについて懸念がある場合は、これで解決します。

ただし、それを置き換えるには不可解な問題も発生します。string.Emptyと比較すると、文字列の長さをテストするよりも効率的なのはなぜですか? それとも、ループが実装されているため、Shinny が使用するテストが無効になっているのでしょうか。(信じがたいことですが、あなたもそうだと思いますが、私も以前騙されたことがあります!)

私は長い間、system.stringオブジェクトはカウント文字列であると考えてきました。これは、基本的に、COM で長い間知られている、長い間確立された Basic String (BSTR) に似ています。

于 2015-12-13T07:13:43.000 に答える
1

Java 1.6 では、String クラスに新しいメソッド [isEmpty] 1が追加されました。

[isBlank] 2メソッドを持つ Jakarta commons ライブラリもあります。空白は、空白のみを含む文字列として定義されます。

于 2008-08-13T19:30:28.063 に答える
1

あなたの質問が.NETであると仮定します:

null に対しても文字列を検証する場合は、IsNullOrEmpty を使用します。たとえば、TextBox.Text などをチェックするときなど、文字列が null ではないことがわかっている場合は、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

つまり、比較は文字列の長さのチェックよりもはるかに重要です。

于 2010-02-21T17:17:42.363 に答える
1

C弦の場合、

if (s[0] == 0)

どちらよりも速くなります

if (strlen(s) == 0)

また

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

関数呼び出しのオーバーヘッドを回避できるからです。

于 2008-08-13T19:51:33.653 に答える
0

実際、IMO が決定する最善の方法は、文字列クラスの IsNullOrEmpty() メソッドです。

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

更新: .Net を想定していましたが、他の言語では、これは異なる可能性があります。

于 2008-08-13T19:06:38.877 に答える
0

繰り返しますが、言語を知らなければ、それを伝えることは不可能です。

ただし、後で作業を保守する必要がある保守プログラマーにとって最も理にかなった手法を選択することをお勧めします。

次のように、必要なことを明示的に行う関数を作成することをお勧めします

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

または同等。今、あなたがチェックしていることに疑いの余地はありません。

于 2008-10-02T17:32:08.123 に答える
0

この場合、新しい空の文字列を作成するオーバーヘッドが回避されるため、長さを直接確認する方が高速です。

@DerekPark: それは常に正しいとは限りません。"" は文字列リテラルであるため、Java ではほぼ確実に既にインターンされています。

于 2008-08-13T19:35:37.680 に答える
0

@ネイサン

実際には、文字列の最初の文字が '\0' であるかどうかを確認する方がよい場合があります。

私はほとんどそれを言及しましたが、空の文字列で呼び出すことstrcmp()と、文字列の最初の文字を直接チェックすることは両方とも O(1) であるため、省略してしまいました。基本的に、追加の関数呼び出しに対して支払うだけで、かなり安価です。ただし、絶対的な最高速度が本当に必要な場合は、最初の文字と 0 を直接比較することをお勧めします。

正直なところ、これが実際に測定可能なパフォーマンスの問題であるプログラムを作成したことがないstrlen() == 0ため、私は常に を使用します。これがチェックを表現する最も読みやすい方法だと思います。

于 2008-08-13T20:00:55.633 に答える