文字列がCの別の文字列で始まるかどうかを確認するにはどうすればよいですか?


85

startsWith(str_a, str_b)標準Cライブラリのようなものはありますか?

nullbytesで終わる2つの文字列へのポインタを取り、最初の文字列が2番目の文字列の先頭にも完全に表示されるかどうかを教えてください。

例:


3
あなたの3番目の例は本当の結果をもたらすはずだと思います。
Michael Burr 2011年

回答:


77

どうやらこれのための標準的なC関数はありません。そう:


上記は素晴らしく明確ですが、タイトなループで実行している場合、または非常に大きな文字列で作業している場合は、両方の文字列の全長を前もってスキャンするため、最高のパフォーマンスは得られません(strlen)。wj32Christophのようなソリューションは、より良いパフォーマンスを提供する可能性があります(ただしベクトル化に関するこのコメントは、私のCの知識を超えています)。また、を回避するFred Fooのソリューションにも注意してください(彼の言う通り、代わりにを使用する場合は不要です)。(非常に)大きな文字列またはタイトなループでの繰り返しの使用にのみ重要ですが、重要な場合は重要です。strlenstrstrncmpmemcmp


5
私がいることを言及する必要があり、通常の文字列は、最初のパラメータであるために事のようになり、そして第二にも接頭辞。しかし、あなたの質問がどのように組み立てられたかのようだったので、私はそれらを上記のように保ちました...順序は完全にあなた次第ですが、私は本当に逆にそれを行うべきでした 'ラウンド-ほとんどの文字列関数は完全な文字列を最初の引数、2番目の部分文字列。
TJ Crowder 2011年

1
これは洗練されたソリューションですが、パフォーマンスの問題がいくつかあります。最適化された実装では、各文字列からmin(strlen(pre)、strlen(str))文字を超える文字を検索したり、最初の不一致を超えて検索したりすることはありません。文字列が長いが、初期の不一致が一般的である場合、それは非常に軽量になります。ただし、この実装では両方の文字列の全長が前面に表示されるため、文字列の最初の文字が異なっていても、最悪の場合のパフォーマンスが強制されます。これが本当に重要かどうかは状況によって異なりますが、潜在的な問題です。
TomKarzes18年

1
@TomKarzesここで置き換えることができmemcmpstrncmpより高速です。両方の文字列に少なくともlenpreバイトがあることがわかっているため、UBはありません。strncmp両方の文字列の各バイトでNULをチェックしますが、strlen呼び出しでは、NULがないことがすでに保証されています。(ただし、実際の一般的な初期シーケンスよりも長い場合、preまたはstrそれよりも長い場合でも、パフォーマンスに
影響があり

1
@ JimBalter-非常に良い点です!memcmp上記を使用しても、ここでの別の回答からは適切ではないため、先に進んで回答を変更しました。
TJCrowder19年

1
PSこれは(現在)いくつかの文字列を持つ一部のマシンで最速の答えである可能性があります。これはstrlenmemcmp非常に高速なハードウェア命令で実装でき、strlensが文字列をキャッシュに入れて、メモリの二重ヒットを回避できるためです。このようなマシンでstrncmpは、2つstrlenのsとmemcmp同じように実装できますが、共通のプレフィックスが短い長い文字列では時間がかかる可能性があるため、ライブラリの作成者がこれを行うのは危険です。ここで、そのヒットは明示的であり、strlensはそれぞれ1回だけ実行されます(Fred Fooのstrlen+strncmpは3を実行します)。
ジムBalter

160

このための標準関数はありませんが、定義することができます

C標準(7.21.4.4/2)によると、str以下のpre理由よりも短くなることを心配する必要はありません。

strncmp機能は以上でないと比較n配列から(ヌル文字に続く文字が比較されていない)文字で指さs1によって指された配列へs2。」


12
なぜ答えはノーですか?明らかに、答えはイエスです、それはと呼ばれていstrncmpます。
ジャスパー

7
^答えがノーである理由は明らかです。「strncmp」strncmpstrlenは呼ばれないものを採用するアルゴリズム。
ジムBalter

34

私はおそらく一緒に行くでしょうがstrncmp()、楽しみのために生の実装:


6
私はこれが一番好きです-どちらかの文字列をスキャンして長さを調べる理由はありません。
Michael Burr 2011年

1
私はおそらくstrlen + strncmpも使用しますが、実際には機能しますが、そのあいまいな定義をめぐるすべての論争は私を先延ばしにしています。だから私はこれを使います、ありがとう。
サムワトキンス2015年

4
strncmpコンパイラがベクトル化に本当に優れている場合を除いて、これはより遅くなる可能性があります。なぜなら、glibcの作成者は確かに:-)
CiroSantilli郝海东冠事病

3
プレフィックスが一致しない場合、特に最初の数文字にすでに違いがある場合、このバージョンはstrlen + strncmpバージョンよりも高速である必要があります。
dpi

1
^その最適化は、関数がインライン化されている場合にのみ適用されます。
ジムBalter

5

私はエレガントなコードを書くのが得意ではありませんが...


5

strstr()関数を使用します。 Stra == strstr(stra, strb)


3
これはやや逆の方法のようです。strbがプレフィックスであるかどうかは非常に短い初期セグメントから明らかであるはずですが、stra全体を通過します。
StasM 2011年

1
時期尚早の最適化はすべての悪の根源です。タイムクリティカルなコードや長い文字列でない場合は、これが最善の解決策だと思います。
フランクバス

1
@ilwこれは有名なコンピューター科学者による有名な言葉です-グーグルで。(それがここにあるように)それはしばしば誤用だ...見joshbarczak.com/blog/?p=580
ジム・Balter

2

最適化(v.2。-修正済み):


2
反対票をstartsWith("\2", "\1")startsWith("\1", "\1")
投じる

instrisincsを使用しないため、この決定ではclangで最適化を使用しません。
ソケットペア2015年

^組み込み関数は、特にターゲット文字列がプレフィックスよりもはるかに長い場合、ここでは役に立ちません。
ジムBalter

1

受け入れられたバージョンを実行し、非常に長いstrで問題が発生したため、次のロジックを追加する必要がありました。


1

または、2つのアプローチの組み合わせ:

編集: strncmpが0を返す場合、終了0または長さ(block_size)に到達したかどうかがわからないため、以下のコードは機能しません

追加のアイデアは、ブロックごとに比較することです。ブロックが等しくない場合は、そのブロックを元の関数と比較します。

定数13644096、などの累乗はblock_size単なる推測です。使用する入力データとハードウェアに合わせて選択する必要があります。


これらは良い考えです。ただし、プレフィックスが12バイト(NULを含めて13)より短い場合、最初の動作は技術的に未定義の動作です。これは、言語標準では、直後のバイト以外の文字列外のアドレスの計算結果が定義されていないためです。
ジムBalter

@JimBalter:参照を追加できますか?ポインターが逆参照され、終了0の後にある場合、差分ポインター値は未定義です。しかし、なぜアドレス自体を未定義にする必要があるのでしょうか。単なる計算です。
SHPC

ただし、一般的なバグがありましたblock_size。インクリメントはポインタのインクリメントの後に行う必要があります。修正されました。
SHPC
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.