std::stringで特定の文字列から開始しているか?をチェックする
最近C言語の文字列を使っているコードをstd::string
を使う C++ のコードに変えるリファクタリングを結構しています。
もちろんどちらを使ってもいいと思いますし、どちらにもメリットとデメリットがありますが、比較に関しては圧倒的にstd::string
の方が優れていると思います。
今回は一番使われる比較のパターンをいくつかを比べてみましょう。
以下のような変数があるとしましょう。
char cWord1[20] = "test1";
char cWord2[20] = "test2";
std::string cppWord1("test1");
std::string cppWord2("test2");
文字列が完全一致かのチェック
if (strcmp(cWord1, cWord2) == 0) {}
if (cppWord1 == cppWord2) {}
単純な等価比較はどちらも割とシンプルですが、C++ の方が関数をコールしなくていいので一番シンプルですね。後、strcmp
は文字列が同じ場合はtrue
に当たる1
ではなく、false
に当たる0
を返すので、そのままif
文の条件として使えなくて、0
と比較しないといけないのが個人的に使いづらいです。
特定の文字列で始まっているかのチェック
if (strncmp(cWord1, cWord2, sizeof(cWord2)) == 0) {}
if (cppWord1.find(cppWord2) == 0) {}
ここはどちらもやり方が色々あると思いますが、個人的に一番使いやすくて短いやり方を比較してみました。strncmp
はかなり万能で、割とどの比較でも使えますが、比較する文字数を渡さないといけないのがこのケースだとちょっと使いづらいですね。ここも C++ の専用の関数の方が使いやすいと思います。
たまにstrncmp
で2つの文字列が完全一致しているかをチェックしているコードを見かけるのですが、文字列がどちらもNULL
終端されていない場合はstrcmp
はクラッシュするまで比較し続けるというエッジケースもあるため、strncmp
の方が無難という認識が強いからかもしれないです。でもstrncmp
を使い際に気を付けないといけないことがあります。例えば、上記の場合は、cWord2
の文字数分しか比較していないため、cWord1
が「test12345」でcWord2
が「test」の場合も、strncmp
は成功してしまいます。なので、strncmp
で完全一致したい場合は、その前に文字数が一致しているかをチェックしないといけないです。
if (sizeof(cWord1) == sizeof(cWord2) && strncmp(cWord1, cWord2, sizeof(cWord2)) == 0) {}
特定の文字列で終わっているかのチェック
if (strncmp(cWord1 + (sizeof(cWord1) - sizeof(cWord2)), cWord2, sizeof(cWord2)) == 0) {}
if (cppWord1.compare(cppWord1.length() - cppWord2.length(), cppWord2.length(), cppWord2) == 0) {}
ここはどちらもあんまり変わらないですね。正直どちらも使いづらいです。
特定の文字列で始まっているかのチェックと特定の文字列で終わっているかのチェックに関しては、C++20 で専用の関数が追加されました。
if (cppWord1.starts_with(cppWord2)) {}
if (cppWord1.ends_with(cppWord2)) {}
なんでこういう便利な関数がもっと早く追加されなかったのだろうという質問は残りますが、ぜひ使ってみてください。
Discussion