文字列がcの別の文字列から始まるかどうかを確認する方法は?
-
22-10-2019 - |
質問
何かがありますか startsWith(str_a, str_b)
標準Cライブラリで?
nullbytesで終わる2つの文字列へのポインターを取り、最初の文字列が2番目の文字列の先頭に完全に表示されるかどうかを教えてください。
例:
"abc", "abcdef" -> true
"abcdef", "abc" -> false
"abd", "abdcef" -> true
"abc", "abc" -> true
解決
どうやら、これには標準C関数はありません。そう:
bool startsWith(const char *pre, const char *str)
{
size_t lenpre = strlen(pre),
lenstr = strlen(str);
return lenstr < lenpre ? false : memcmp(pre, str, lenpre) == 0;
}
上記は素晴らしくて明確であるが、あなたがそれをタイトなループでやっているか、一緒に作業していることに注意してください とても 大きな文字列、それは前に両方の文字列の完全な長さをスキャンするので、最高のパフォーマンスを提供しないかもしれません(strlen
)。のようなソリューション WJ32 また クリストフ より良いパフォーマンスを提供する可能性があります(ただし このコメント ベクトル化については、私のケンのc)を超えています。また、注意してください フレッド・フーのソリューション これは避けています strlen
の上 str
(彼は正しい、あなたが使用する場合、それは不要です strncmp
それ以外の memcmp
)。 (非常に)大きな文字列またはタイトなループでの繰り返しの使用のみが重要ですが、それが重要な場合は重要です。
他のヒント
これには標準機能はありませんが、定義できます
bool prefix(const char *pre, const char *str)
{
return strncmp(pre, str, strlen(pre)) == 0;
}
心配する必要はありません str
より短い pre
C標準(7.21.4.4/2)によると:
strncmp
関数は比較しませんn
に向けられた配列からの文字(ヌル文字に続く文字は比較されません)s1
に向けられた配列にs2
."
おそらく一緒に行くでしょう strncmp()
, 、しかし楽しいために生の実装:
_Bool starts_with(const char *restrict string, const char *restrict prefix)
{
while(*prefix)
{
if(*prefix++ != *string++)
return 0;
}
return 1;
}
私はエレガントなコードを書くことの専門家ではありませんが...
int prefix(const char *pre, const char *str)
{
char cp;
char cs;
if (!*pre)
return 1;
while ((cp = *pre++) && (cs = *str++))
{
if (cp != cs)
return 0;
}
if (!cs)
return 0;
return 1;
}
使用する strstr()
関数。 Stra == strstr(stra, strb)
最適化(v.2。-修正):
uint32 startsWith( const void* prefix_, const void* str_ ) {
uint8 _cp, _cs;
const uint8* _pr = (uint8*) prefix_;
const uint8* _str = (uint8*) str_;
while ( ( _cs = *_str++ ) & ( _cp = *_pr++ ) ) {
if ( _cp != _cs ) return 0;
}
return !_cp;
}
私は受け入れられたバージョンを実行し、非常に長いSTRで問題を抱えていたので、次のロジックを追加する必要がありました。
bool longEnough(const char *str, int min_length) {
int length = 0;
while (str[length] && length < min_length)
length++;
if (length == min_length)
return true;
return false;
}
bool startsWith(const char *pre, const char *str) {
size_t lenpre = strlen(pre);
return longEnough(str, lenpre) ? strncmp(str, pre, lenpre) == 0 : false;
}
または2つのアプローチの組み合わせ:
_Bool starts_with(const char *restrict string, const char *restrict prefix)
{
char * const restrict prefix_end = prefix + 13;
while (1)
{
if ( 0 == *prefix )
return 1;
if ( *prefix++ != *string++)
return 0;
if ( prefix_end <= prefix )
return 0 == strncmp(prefix, string, strlen(prefix));
}
}
編集: 以下のコードはそうです いいえ strncmpが0を返す場合、終了0または長さ(block_size)に到達したかどうかは不明であるためです。
追加のアイデアは、ブロックを比較することです。ブロックが等しくない場合、そのブロックを元の関数と比較してください。
_Bool starts_with_big(const char *restrict string, const char *restrict prefix)
{
size_t block_size = 64;
while (1)
{
if ( 0 != strncmp( string, prefix, block_size ) )
return starts_with( string, prefix);
string += block_size;
prefix += block_size;
if ( block_size < 4096 )
block_size *= 2;
}
}
定数 13
, 64
, 4096
, 、およびの指数化と同様に block_size
推測だけです。使用した入力データとハードウェアに対して選択する必要があります。