C++で文字列を比較する際のベストプラクティス:std::strncmpを超えて


機能

  • 比較対象文字列が NULL 文字 (\0) で終わっていない場合でも、正しく動作します。
  • 文字列の比較は、辞書順(アルファベット順)で行われます。
  • 指定された count 文字までの比較を行います。
  • 2つの C 言語スタイルの文字列 (str1str2) を比較します。

戻り値

  • str1str2 より大きい場合:正の整数
  • str1str2 が等しい場合:0
  • str1str2 より小さい場合:負の整数

#include <iostream>
#include <cstring>

int main() {
  const char* str1 = "Hello";
  const char* str2 = "World";
  size_t count = 5;

  int result = std::strncmp(str1, str2, count);

  if (result < 0) {
    std::cout << str1 << " は " << str2 << " より小さいです。" << std::endl;
  } else if (result == 0) {
    std::cout << str1 << " と " << str2 << " は等しいです。" << std::endl;
  } else {
    std::cout << str1 << " は " << str2 << " より大きいです。" << std::endl;
  }

  return 0;
}

この例では、std::strncmp 関数は最初の 5 文字 ("Hell") を比較します。HelloWorld より小さいので、結果は負の整数になります。

  • std::strncmp 関数は、比較対象文字列が NULL 文字 (\0) で終わっていない場合でも、正しく動作します。ただし、このような文字列を比較する場合は、count パラメータに注意する必要があります。count パラメータが NULL 文字までの文字数よりも大きい場合、std::strncmp 関数は NULL 文字を比較対象に含めてしまいます。
  • std::strncmp 関数は、文字列の先頭部分のみを比較するため、2つの文字列が完全に等しいかどうかを確認するには適していません。完全な比較には、strcmp 関数を使用する必要があります。


文字列の先頭部分を比較する

#include <iostream>
#include <cstring>

int main() {
  const char* str1 = "Hello, World!";
  const char* str2 = "Hello, Universe!";
  size_t count = 7; // 先頭 7 文字を比較

  int result = std::strncmp(str1, str2, count);

  if (result < 0) {
    std::cout << str1 << " は " << str2 << " より小さいです。" << std::endl;
  } else if (result == 0) {
    std::cout << str1 << " と " << str2 << " は先頭 " << count << " 文字まで等しいです。" << std::endl;
  } else {
    std::cout << str1 << " は " << str2 << " より大きいです。" << std::endl;
  }

  return 0;
}

この例では、std::strncmp 関数は str1str2 の先頭 7 文字を比較します。2つの文字列の先頭 6 文字 ("Hello, ") は等しいので、結果は 0 になります。

文字列の一部を比較して、一致する部分を見つける

#include <iostream>
#include <cstring>

int main() {
  const char* str1 = "This is a test string.";
  const char* str2 = "test";
  size_t count = strlen(str2); // str2 の長さだけ比較

  int pos = std::strncmp(str1, str2, count);

  if (pos == 0) {
    std::cout << "\"" << str2 << "\"" << " は " << str1 << " の先頭 " << count << " 文字に一致します。" << std::endl;
  } else {
    std::cout << "\"" << str2 << "\"" << " は " << str1 << " に一致しません。" << std::endl;
  }

  return 0;
}

この例では、std::strncmp 関数は str1 の先頭部分と str2 を比較します。str2str1 の先頭 4 文字 ("This") に一致するので、結果は 0 になります。

#include <iostream>
#include <cstring>
#include <string>

int main() {
  std::string str1 = "Hello, World!";
  std::string str2 = "hElLo, wORlD!";

  int result = std::strncmp(str1.c_str(), str2.c_str(), str1.length());

  if (result < 0) {
    std::cout << str1 << " は " << str2 << " より小さいです。" << std::endl;
  } else if (result == 0) {
    std::cout << str1 << " と " << str2 << " は等しいです。" << std::endl;
  } else {
    std::cout << str1 << " は " << str2 << " より大きいです。" << std::endl;
  }

  return 0;
}

この例では、std::string クラスの c_str() メンバ関数を使用して、C 言語スタイルの文字列を取得してから、std::strncmp 関数で比較します。std::string クラスの compare() メンバ関数を使用すると、大文字小文字を無視した比較をより簡単に実行できます。

これらの例は、std::strncmp 関数の基本的な使用方法を示しています。この関数は、様々な目的に使用できる汎用性の高いツールです。

  • エラー処理は省略されていますが、本番コードでは適切なエラー処理を実装する必要があります。
  • コード例では、文字列リテラルを使用していますが、実際のプログラムでは変数に格納された文字列を使用する方が一般的です。
  • 上記のコード例は、コンパイルと実行のために必要なヘッダーファイル (<iostream><cstring>) をインクルードしています。


std::string クラスを使用する

C++ の標準ライブラリには、std::string クラスと呼ばれる強力な文字列操作用クラスが用意されています。std::string クラスには、文字列の比較、検索、操作などを行うための様々なメンバ関数が用意されています。

std::strncmp の代替として std::string クラスを使用する主な利点は以下の通りです。

  • 機能が豊富: std::string クラスには、std::strncmp では利用できない様々な機能が備わっています。
  • 安全: std::string クラスは、バッファオーバーフローなどのメモリ関連のエラーを防ぐための機能が備わっています。
  • 使い方が簡単: std::string クラスは、C 言語スタイルの文字列よりも使い方が簡単で、コードが読みやすくなります。

以下に、std::strncmpstd::string クラスの compare() メンバ関数で置き換える方法の例を示します。

#include <iostream>
#include <string>

int main() {
  std::string str1 = "Hello, World!";
  std::string str2 = "Hello, Universe!";

  int result = str1.compare(str2);

  if (result < 0) {
    std::cout << str1 << " は " << str2 << " より小さいです。" << std::endl;
  } else if (result == 0) {
    std::cout << str1 << " と " << str2 << " は等しいです。" << std::endl;
  } else {
    std::cout << str1 << " は " << str2 << " より大きいです。" << std::endl;
  }

  return 0;
}

std::string_view クラスを使用する

std::string_view クラスは、std::string クラスと似ていますが、メモリを所有しない点が異なります。つまり、std::string_view オブジェクトは、別の文字列バッファを参照するだけで作成されます。

  • メモリ効率が高い: std::string_view クラスはメモリを所有しないため、メモリ使用量を削減できます。
  • 軽量: std::string_view クラスは std::string クラスよりも軽量で、パフォーマンスが向上します。
#include <iostream>
#include <string_view>

int main() {
  const char* str1_data = "Hello, World!";
  std::size_t str1_length = strlen(str1_data);
  std::string_view str1(str1_data, str1_length);

  const char* str2_data = "Hello, Universe!";
  std::size_t str2_length = strlen(str2_data);
  std::string_view str2(str2_data, str2_length);

  int result = str1.compare(str2);

  if (result < 0) {
    std::cout << str1 << " は " << str2 << " より小さいです。" << std::endl;
  } else if (result == 0) {
    std::cout << str1 << " と " << str2 << " は等しいです。" << std::endl;
  } else {
    std::cout << str1 << " は " << str2 << " より大きいです。" << std::endl;
  }

  return 0;
}

カスタム比較関数を使用する

std::strncmp 以外の方法で文字列を比較したい場合は、カスタム比較関数を作成することができます。この方法は、特殊な比較規則が必要な場合に役立ちます。

以下に、大文字小文字を無視して文字列を比較するカスタム比較関数の例を示します。

#include <iostream>
#include <algorithm>
#include <cctype>

bool case_insensitive_