大文字と小文字


85

大文字と小文字を区別しない比較を行う場合、文字列を大文字または小文字に変換する方が効率的ですか?それも重要ですか?

このSOの投稿では、「Microsoftがそのように最適化した」ため、ToUpperの方がC#の方が効率的であることが示唆さています。しかし、ToLowerとToUpperの変換は、文字列に含まれる内容に依存し、通常、文字列には小文字が多く含まれるため、ToLowerがより効率的になるというこの引数も読みました。

特に、私は知りたいです:

  • ToUpperまたはToLowerを最適化して、一方が他方よりも高速になるようにする方法はありますか?
  • 大文字または小文字の文字列間で大文字と小文字を区別しない比較を行う方が高速ですか。その理由は何ですか。
  • あるケースが他のケースよりも明らかに優れているプログラミング環境(C、C#、Pythonなど)はありますか?その理由は何ですか?

回答:


90

大文字と小文字を区別しない比較を行うために大文字または小文字に変換することは、一部の文化、特にトルコの「興味深い」機能のために正しくありません。代わりに、適切なオプションを指定してStringComparerを使用してください。

MSDNには、文字列の処理に関する優れたガイドラインがいくつかあります。また、コードがトルコの検定に合格することを確認することもできます。

編集:通常の大文字と小文字を区別しない比較に関するNeilのコメントに注意してください。この領域全体はかなり曖昧です:(


15
はいStringComparerは素晴らしいですが、質問には答えられませんでした...文字列に対するswtichステートメントなどのStringComparerを使用できない状況では。スイッチでTo​​UpperまたはToLowerを使用する必要がありますか?
joshperry 2009

7
ToUpperまたはToLowerを使用する代わりに、StringComparerと「if」/「else」を使用します。
Jon Skeet

5
ジョン、小文字への変換が間違っていることは知っていますが、大文字への変換が間違っているとは聞いていませんでした。例や参考資料を提供できますか?リンクしたMSDNの記事には、「OrdinalIgnoreCaseを使用して行われた比較は、動作上、両方の文字列引数でToUpperInvariantを呼び出すことと、序数の比較を行うことの2つの呼び出しの合成です」と書かれています。「序数文字列操作」というタイトルのセクションでは、これをコードで言い換えています。
ニール

2
@ニール:興味深いことに、私はそのビットを見ていませんでした。大文字と小文字を区別しない比較、私はそれが公正十分だと思います。結局のところ、何かを選ぶ必要あります。大文字と小文字を区別しない文化的な比較の場合、奇妙な動作の余地はまだあると思います。...その答えにあなたのコメントを指摘する
ジョンスキート

4
@Triynko:間違った答えを早く得ることは、間違った答えをゆっくりと得ることよりも通常は良くない(そして時には悪い)という点で、に正しさに集中することが重要だと思います。
Jon Skeet 2011

25

MSDNのMicrosoftから:

.NETFrameworkで文字列を使用するためのベストプラクティス

文字列の使用に関する推奨事項

どうして?マイクロソフトから:

文字列を大文字に正規化する

小文字に変換すると往復できない文字の小さなグループがあります。

往復できないキャラクターの例は?

  • 開始:ギリシャ語のロー記号(U + 03f1)ϱ
  • 大文字: Capital Greek Rho(U + 03a1)Ρ
  • 小文字:小さなギリシャ文字のロー(U + 03c1)ρ

ϱ、 Ρρ

.NETフィドル

Original: ϱ
ToUpper: Ρ
ToLower: ρ

そのため、大文字と小文字を区別しない比較を行う場合は、文字列を小文字ではなく大文字に変換します。

したがって、1つを選択する必要がある場合は、大文字を選択してください。


そしてその理由は何ですか?
bjan 2013

@bjan理由はそうしないのは悪いからです。
イアン・ボイド

1
どのグループのキャラクターですか?往復とはどういう意味ですか?
johv 2014

1
@johvリンクから:「ラウンドトリップを行うとは、あるロケールから文字データを異なる方法で表す別のロケールに文字を変換し、変換された文字から元の文字を正確に取得することを意味します。」 どのグループのキャラクターですか?わかりませんが、iトルコ語の小文字İI、あなたが慣れているものではなく、いつになるかを推測します。また、大文字にIなるのiに慣れていますが、トルコではı。になります。
イアン・ボイド

3
元の質問の答えに戻る:1つの大文字のバリアントに対して複数の小文字のバリアントを知っている言語があります。どの表現をいつ使用するかについての規則を知らない限り(ギリシャ語の別の例:小さなシグマ文字、単語の最初または途中でσ、単語の最後でσを使用します(en.wikipedia.org/wiki/Sigmaを参照)、あなたは安全に戻っ小文字のバリアントに変換することはできません。
アコンカグア

19

MSDNによると、文字列を渡して、大文字と小文字を区別しないように比較する方が効率的です。

String.Compare(strA、strB、StringComparison.OrdinalIgnoreCase)は、呼び出しと同等です(ただし、より高速です)。

String.Compare(ToUpperInvariant(strA)、ToUpperInvariant(strB)、StringComparison.Ordinal)。

これらの比較はまだ非常に高速です。

もちろん、1つの文字列を何度も比較している場合、これは当てはまらない可能性があります。


12

小文字のエントリが多い傾向にある文字列に基づくと、ToLowerは理論的には高速であるはずです(比較はたくさんありますが、割り当てはほとんどありません)。

Cの場合、または各文字列の個別にアクセス可能な要素(C文字列やC ++のSTLの文字列型など)を使用する場合、実際にはバイト比較です。したがって、比較UPPERはと同じlowerです。

卑劣で文字列をlong配列にロードした場合、一度に4バイトを比較できるため、文字列全体を非常に高速に比較できます。ただし、ロード時間によって価値がなくなる場合があります。

どちらが速いのかを知る必要があるのはなぜですか?比較のメトリックバットロードを実行していない限り、数サイクル速く実行するものは、全体的な実行の速度とは無関係であり、時期尚早の最適化のように聞こえます:)


11
どちらが速いのかを知る必要がある理由という質問に答えるには、知る必要はありません。単に知りたいだけです。:)それは、誰かが主張をしているのを見て(「大文字の文字列を比較する方が速い!」など)、それが本当に真実かどうか、および/またはなぜ彼らがその主張をしたのかを知りたいという場合です。
パラッパ

1
それは理にかなっています-私もこのようなものに永遠に興味があります:)
ウォーレン

変換するC文字列とsし、t文字列は配列IFF等しくなるようにlong型の配列にあなたが終端見つけるまで、sとtを歩いする必要が等しい場合'\0'、あなたが文字列の終わりを過ぎてゴミを比較するかもしれない文字(または他のこれは、未定義の動作を引き起こす不正なメモリアクセスである可能性があります)。では、キャラクターを1つずつ歩きながら比較してみませんか?C ++文字列を使用すると.c_str()、おそらく長さとを取得し、にキャストしてlong *、長さのプレフィックスを比較できます.size() - .size()%(sizeof long)。私には少し怪しげに見えます、トー。
ジョナスKölker

6

Microsoftは最適化しましたがToUpperInvariant()、ではありませんToUpper()。違いは、不変条件の方が文化に優しいということです。カルチャが異なる可能性のある文字列で大文字と小文字を区別しない比較を行う必要がある場合は、Invariantを使用してください。そうでない場合は、不変変換のパフォーマンスは重要ではありません。

ToUpper()とToLower()のどちらが速いかはわかりませんが。パフォーマンスがそれほど重要な状況になったことがないので、試したことはありません。


Microsoftが大文字の比較を実行するためにコードを最適化した場合、大文字のASCIIコードは65〜90の2桁のみであるのに対し、ASCIIコードは3桁を含む小文字の97〜122(より多くの処理が必要)であるためですか?
Medo Medo 2016

3
@Medo最適化の正確な理由は覚えていませんが、すべての文字が2進数として格納されるため、2桁と3桁はほぼ確実に理由ではありません。したがって、10進数は、格納方法に基づいて実際には意味がありません。
ダンハーバート

4

C#で文字列の比較を行う場合は、両方の文字列を大文字または小文字に変換する代わりに、.Equals()を使用する方がはるかに高速です。.Equals()を使用するもう1つの大きな利点は、2つの新しい大文字/小文字の文字列に割り当てられるメモリが増えないことです。


4
そしてボーナスとして、あなたが正しいオプションを選ぶならば、それは実際にあなたに正しい結果を与えるでしょう:)
Jon Skeet

1

それは本当に問題ではないはずです。ASCII文字の場合、それは間違いなく重要ではありません-それはほんの数回の比較であり、どちらの方向にも少し反転します。Unicodeは、大文字と小文字が奇妙に変わる文字があるため、もう少し複雑になる可能性がありますが、テキストがそれらの特殊文字でいっぱいでない限り、実際には違いはありません。


1

正しく行うと、小文字に変換すると速度がわずかに向上するはずですが、多くの人が示唆しているように、これは文化に依存し、関数ではなく変換する文字列(多くの小文字)に継承されます。メモリへの割り当てが少ないことを意味します)-大文字がたくさんある文字列がある場合、大文字への変換が速くなります。


0

場合によります。上で述べたように、ASCIIのみをプレーンにします。.NETで、Stringについて読んで使用します。i18nのもの(言語カルチャとユニコード)の正しいものを比較します。入力の可能性について何か知っている場合は、より一般的なケースを使用してください。

複数の文字列を比較する場合は、長さが優れた最初の識別器であることを忘れないでください。


-2

純粋なASCIIを扱っている場合、それは問題ではありません。これは、OR x、32対AND x、224です。Unicode、わかりません...


4
これは完全に間違っています-32でORを実行すると、AZと文字64〜127でのみ機能します。それは他のすべての文字を台無しにします。32とのAND演算はさらに間違っています。結果は、常に0(ヌル)または32(スペース)になります。
アダムローゼンフィールド
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.