【Qt入門】QStringとQListにおけるcontains()の使い方と注意点

2025-06-06

Qtにおいてcontains()という名前のメソッドは、コレクションクラス(リスト、マップ、セットなど)のインスタンスが特定の要素を含んでいるかどうかをチェックするために使用されます。ユーザーが言及されている「Item.contains()」が具体的にどのクラスのメソッドを指しているかによって少し意味合いが変わりますが、最も一般的なケースは以下の2つです。

  1. QStandardItem クラスには直接 contains() メソッドはありません。 ユーザーが「Item.contains()」と仰っている場合、これはおそらくQStandardItemオブジェクトが含まれているコレクション(例: QList<QStandardItem*>QVector<QStandardItem>など)に対してcontains()を呼び出すことを意図しているか、あるいはQStandardItemデータ内容(例えば、文字列データが特定のサブ文字列を含むか)をチェックすることを意図している可能性があります。

    もし後者の、QStandardItemが持つ文字列データが特定のサブ文字列を含むかをチェックしたいのであれば、QStandardItem::text()メソッドで文字列を取得し、そのQStringオブジェクトのcontains()メソッドを使用します。

    #include <QStandardItem>
    #include <QString>
    #include <QDebug>
    
    int main() {
        QStandardItem* item = new QStandardItem("Hello World");
    
        // QStandardItemが持つ文字列データが"World"を含むかチェック
        if (item->text().contains("World")) {
            qDebug() << "Item text contains 'World'.";
        } else {
            qDebug() << "Item text does not contain 'World'.";
        }
    
        // 大文字・小文字を区別しないチェック
        if (item->text().contains("world", Qt::CaseInsensitive)) {
            qDebug() << "Item text contains 'world' (case-insensitive).";
        }
    
        delete item;
        return 0;
    }
    
  2. Qtのコレクションクラス(QList, QVector, QSetなど)の contains() メソッド。 これは、特定の要素がコレクション内に存在するかどうかを確認するための非常に一般的なメソッドです。

    例: QList::contains() の使用

    #include <QList>
    #include <QString>
    #include <QDebug>
    
    int main() {
        QList<QString> myList;
        myList << "Apple" << "Banana" << "Cherry";
    
        // "Banana"がリストに含まれているかチェック
        if (myList.contains("Banana")) {
            qDebug() << "List contains 'Banana'.";
        } else {
            qDebug() << "List does not contain 'Banana'.";
        }
    
        // "Grape"がリストに含まれているかチェック
        if (myList.contains("Grape")) {
            qDebug() << "List contains 'Grape'.";
        } else {
            qDebug() << "List does not contain 'Grape'.";
        }
    
        QList<int> myIntList;
        myIntList << 10 << 20 << 30;
    
        // 20が整数リストに含まれているかチェック
        if (myIntList.contains(20)) {
            qDebug() << "Int list contains 20.";
        }
    
        return 0;
    }
    
  • もしQStandardItemオブジェクトが含まれるリストやコンテナに対して検索を行いたい場合は、そのコンテナクラス(例: QList<QStandardItem*>)のcontains()メソッドを使います。
  • もしQStandardItemオブジェクトのテキスト内容を検索したい場合は、item->text().contains("...")のようにQStringcontains()メソッドを使います。
  • QStandardItemクラス自体には直接contains()メソッドは存在しません。


前回の説明で触れたように、QStandardItem自体には直接contains()メソッドはありません。したがって、ここで言う「Item.contains()」は、主にQStringオブジェクトのcontains()や、QListなどのコレクションクラスが特定の要素を含むかをチェックするcontains()メソッドについて想定して説明します。

QString::contains() に関連するエラーとトラブルシューティング

これは、文字列が特定のサブ文字列を含むかを確認する際によく使われます。

一般的なエラー

  • ヌルポインタまたは無効なQString
    QStringオブジェクトが有効でない(例えば、未初期化のポインタが指す先のQStringに対してcontains()を呼び出す)場合、クラッシュ(Segmentation Fault)を引き起こす可能性があります。
  • エンコーディングの問題
    異なる文字エンコーディングの文字列を比較しようとすると、期待しない結果になることがあります。特にファイルから読み込んだり、ネットワーク経由で受け取った文字列を扱う場合に発生しやすいです。
  • 意図しない空白文字
    検索対象の文字列や比較対象のサブ文字列に、目に見えない空白文字(スペース、タブ、改行など)が含まれている場合、期待通りの結果が得られないことがあります。 例: " Hello ".contains("Hello")false となる場合があります(正確には、" Hello ".trimmed().contains("Hello") のようにする必要があります)。
  • 大文字・小文字の区別
    contains()はデフォルトで大文字・小文字を区別します。 例: "Hello".contains("hello")false を返します。

トラブルシューティング

  • ヌルポインタチェック
    ポインタを使用している場合は、contains()を呼び出す前にヌルチェックを行います。
    QStandardItem* item = ...; // QStandardItemのポインタ
    if (item && item->text().contains("some_text")) {
        // 安全にcontains()を呼び出す
    }
    
  • 文字列の正規化
    文字エンコーディングの問題が疑われる場合は、QString::normalized()や適切なエンコーディング変換(QString::fromLocal8Bit(), QString::toUtf8()など)を検討します。
  • デバッグ出力
    qDebug()を使用して、検索対象の文字列と比較対象のサブ文字列を正確に確認します。特に空白文字や非表示文字の存在を確認するのに役立ちます。
    QString myText = item->text(); // あるいは他のQString
    QString searchTerm = "探したい文字列";
    qDebug() << "My text:" << myText;
    qDebug() << "Search term:" << searchTerm;
    if (myText.contains(searchTerm)) {
        // ...
    }
    
  • 文字列のトリム
    比較を行う前に、QString::trimmed()を使用して文字列の先頭と末尾の空白文字を削除します。
    QString str = "  Hello World  ";
    if (str.trimmed().contains("Hello")) {
        // 期待通り "Hello" が見つかる
    }
    
  • 大文字・小文字の区別を無視する
    contains()のオーバーロードを使用し、Qt::CaseInsensitiveフラグを渡します。
    QString str = "Hello World";
    if (str.contains("world", Qt::CaseInsensitive)) {
        // "world" が見つかる
    }
    

コレクションクラス(QList, QVector, QSetなど)の contains() に関連するエラーとトラブルシューティング

これは、リストやセットが特定の要素を含むかを確認する際に使われます。

一般的なエラー

  • 一時オブジェクト
    検索する要素を一時オブジェクトとして作成し、それがコレクション内の要素と異なるタイプまたは参照である場合に問題が発生することがあります。
  • ポインタの比較
    QList<MyClass*>のようにポインタを格納している場合、contains()はポインタのアドレスを比較します。つまり、異なるオブジェクトだが内容が同じである場合はfalseを返します。
    QList<MyClass*> myList;
    MyClass* obj1 = new MyClass{1, "Apple"};
    myList.append(obj1);
    
    MyClass* obj2 = new MyClass{1, "Apple"}; // obj1とは異なるメモリアドレス
    if (myList.contains(obj2)) { // false を返す (アドレスが異なるため)
        // 意図しない結果
    }
    
  • カスタムクラスの比較
    QList<MyCustomClass>のようにカスタムクラスのオブジェクトを格納している場合、contains()が正しく機能するためには、そのカスタムクラスにoperator==がオーバーロードされている必要があります。contains()は内部でoperator==を使用して要素の等価性を判断するからです。
    class MyClass {
    public:
        int id;
        QString name;
        // ...
        bool operator==(const MyClass& other) const {
            return (id == other.id && name == other.name); // 適切な比較ロジック
        }
    };
    
    QList<MyClass> myList;
    myList.append(MyClass{1, "Apple"});
    MyClass searchItem{1, "Apple"};
    if (myList.contains(searchItem)) { // operator== が呼ばれる
        // ...
    }
    
  • より適切なコンテナの選択
    特定のキーでオブジェクトを効率的に検索したい場合は、QMap<KeyType, ValueType>QHash<KeyType, ValueType>の使用を検討してください。これらはキーに基づく高速な検索を提供します。
    QMap<int, MyClass*> myMap;
    MyClass* obj1 = new MyClass{1, "Apple"};
    myMap.insert(obj1->id, obj1);
    
    if (myMap.contains(1)) { // id 1 のオブジェクトが存在するかチェック
        qDebug() << "Map contains item with id 1.";
    }
    // ...
    qDeleteAll(myMap);
    
  • ポインタリストの検索
    QList<MyClass*>のようにポインタのリストでオブジェクトの内容を検索したい場合は、std::find_ifやQtのイテレータとラムダ関数を組み合わせて、各ポインタが指すオブジェクトの内容を比較する必要があります。
    QList<MyClass*> myList;
    myList.append(new MyClass{1, "Apple"});
    myList.append(new MyClass{2, "Banana"});
    
    MyClass searchCriteria{1, "Apple"}; // 検索条件となるオブジェクト
    
    // ラムダ式を使って内容で検索
    auto it = std::find_if(myList.begin(), myList.end(),
                           [&](MyClass* item) {
                               return item->id == searchCriteria.id &&
                                      item->name == searchCriteria.name;
                           });
    
    if (it != myList.end()) {
        qDebug() << "Found item by content.";
    } else {
        qDebug() << "Item not found by content.";
    }
    
    // リストの要素を解放することを忘れない
    qDeleteAll(myList);
    
  • カスタムクラスのoperator==のオーバーロード
    カスタムクラスをQListQSetに格納してcontains()を使用する場合、必ずoperator==を適切にオーバーロードしてください。この演算子は、そのクラスのオブジェクトが「等しい」と見なされる条件を定義します。

全般的なトラブルシューティングのヒント

  • Qtのドキュメントを確認
    使用しているcontains()メソッドの正確なシグネチャと挙動をQtの公式ドキュメントで確認します。特にテンプレート型を使用している場合、型の要件(例えば、operator==の存在)が明記されていることがあります。
  • 最小限の再現コード
    問題が複雑な場合、問題が発生している部分だけを切り出した最小限のコードを作成し、独立してテストすることで、原因を特定しやすくなります。
  • qDebug()による出力
    デバッガを使用できない環境や、より手軽に確認したい場合は、qDebug()を使って中間結果や変数の内容をコンソールに出力します。
  • デバッガの活用
    最も効果的なのは、コードにブレークポイントを設定し、contains()が呼び出される直前の変数(検索対象の文字列やリスト、比較対象の要素)の内容をデバッガで確認することです。これにより、期待通りの値が渡されているか、誤った値が含まれていないかを視覚的に確認できます。


ここでは、主に以下の2つのパターンに焦点を当てて説明します。

  1. QStandardItemのテキストデータが特定の文字列を含むかを確認する (QString::contains())
  2. QListなどのコンテナが特定の要素(QStandardItem*や他の型)を含むかを確認する (QList::contains())

例1: QStandardItemのテキストデータに特定の文字列が含まれるかチェックする

この例では、QStandardItemが持つテキスト(item->text()で取得できるQString)に対してQString::contains()メソッドを使用します。

#include <QApplication> // Qtアプリケーションの基本的なフレームワーク
#include <QStandardItemModel> // アイテムモデルの基本的なクラス
#include <QStandardItem>    // モデル内の個々のアイテムを表すクラス
#include <QDebug>           // デバッグ出力用

int main(int argc, char *argv[]) {
    QApplication app(argc, argv);

    // QStandardItemModelを作成(ここでは単純な例なのでビューは作成しない)
    QStandardItemModel model;

    // いくつかのQStandardItemを作成し、テキストを設定
    QStandardItem *item1 = new QStandardItem("Apple");
    QStandardItem *item2 = new QStandardItem("Banana Smoothie");
    QStandardItem *item3 = new QStandardItem("Cherry Pie");
    QStandardItem *item4 = new QStandardItem("Orange Juice");

    // アイテムをモデルに追加 (この例では直接モデルに追加していますが、QListに入れることも可能です)
    // 実際には、例えば QModelIndex を使ってアイテムにアクセスすることが多いです。
    // 今回は例のために、直接アイテムポインタを使います。

    qDebug() << "--- QStandardItem::text().contains() の例 ---";

    // item1 のテキストに "App" が含まれるか?
    if (item1->text().contains("App")) {
        qDebug() << "Item 1 ('" << item1->text() << "') contains 'App'.";
    } else {
        qDebug() << "Item 1 ('" << item1->text() << "') does NOT contain 'App'.";
    }

    // item2 のテキストに "Smoothie" が含まれるか?(大文字・小文字を区別)
    if (item2->text().contains("Smoothie")) {
        qDebug() << "Item 2 ('" << item2->text() << "') contains 'Smoothie'.";
    } else {
        qDebug() << "Item 2 ('" << item2->text() << "') does NOT contain 'Smoothie'.";
    }

    // item3 のテキストに "pie" が含まれるか?(大文字・小文字を区別しない)
    if (item3->text().contains("pie", Qt::CaseInsensitive)) {
        qDebug() << "Item 3 ('" << item3->text() << "') contains 'pie' (case-insensitive).";
    } else {
        qDebug() << "Item 3 ('" << item3->text() << "') does NOT contain 'pie' (case-insensitive).";
    }

    // item4 のテキストに "Grape" が含まれるか?
    if (item4->text().contains("Grape")) {
        qDebug() << "Item 4 ('" << item4->text() << "') contains 'Grape'.";
    } else {
        qDebug() << "Item 4 ('" << item4->text() << "') does NOT contain 'Grape'.";
    }

    // itemを解放 (この例ではQStandardItemModelが所有権を持つため、手動でのdeleteは不要です)
    // しかし、QListなどに直接QStandardItemポインタを格納した場合、手動で解放する必要があります。
    // item1, item2, item3, item4 は QStandardItemModel に追加されていないので、ここでは手動で解放します。
    // もしモデルに追加した場合は、モデルが所有権を持つのでdeleteは不要です。
    // ここではデモンストレーションのため直接newしているので、deleteします。
    delete item1;
    delete item2;
    delete item3;
    delete item4;

    return app.exec(); // イベントループを開始(この例ではUIがないためすぐに終了します)
}

解説

  • QString::contains("...", Qt::CaseInsensitive): Qt::CaseInsensitiveフラグを渡すことで、大文字・小文字を区別せずに検索できます。
  • QString::contains("..."): 取得したQStringが指定された部分文字列を含むかどうかをチェックします。
  • item->text(): QStandardItemオブジェクトが持つ文字列データをQStringとして取得します。

例2: QListに特定のQStandardItemポインタが含まれるかチェックする

この例では、QStandardItemポインタのリスト(QList<QStandardItem*>)が特定のポインタを保持しているかを確認するためにQList::contains()を使用します。

#include <QApplication>
#include <QStandardItem>
#include <QList>
#include <QDebug>

int main(int argc, char *argv[]) {
    QApplication app(argc, argv);

    QStandardItem *itemA = new QStandardItem("Red");
    QStandardItem *itemB = new QStandardItem("Green");
    QStandardItem *itemC = new QStandardItem("Blue");
    QStandardItem *itemD = new QStandardItem("Yellow"); // リストには追加しないアイテム

    // QStandardItemポインタのリストを作成
    QList<QStandardItem*> myItemList;
    myItemList.append(itemA);
    myItemList.append(itemB);
    myItemList.append(itemC);

    qDebug() << "--- QList<QStandardItem*>::contains() の例 ---";

    // itemA がリストに含まれているか?
    if (myItemList.contains(itemA)) {
        qDebug() << "List contains itemA (address: " << itemA << ").";
    } else {
        qDebug() << "List does NOT contain itemA.";
    }

    // itemD がリストに含まれているか?
    if (myItemList.contains(itemD)) {
        qDebug() << "List contains itemD (address: " << itemD << ").";
    } else {
        qDebug() << "List does NOT contain itemD.";
    }

    // 新しいQStandardItemを作成。内容は itemA と同じだが、異なるメモリアドレス。
    QStandardItem *anotherItemA = new QStandardItem("Red");
    // この anotherItemA はリストに含まれていない(メモリアドレスが異なるため)
    if (myItemList.contains(anotherItemA)) {
        qDebug() << "List contains anotherItemA (address: " << anotherItemA << ").";
    } else {
        qDebug() << "List does NOT contain anotherItemA (address: " << anotherItemA << ").";
    }

    // リスト内のすべてのアイテムと、一時的に作成したアイテムを解放
    // QList<T*> を扱う場合、要素の削除(delete)は手動で行う必要があります。
    // qDeleteAll は QList<T*> のすべての要素をdeleteする便利な関数です。
    qDeleteAll(myItemList); // myItemList内のitemA, itemB, itemCを解放
    myItemList.clear();     // リストを空にする
    delete itemD;           // リストに追加しなかったitemDを解放
    delete anotherItemA;    // 一時的に作成したanotherItemAを解放

    return app.exec();
}

解説

  • qDeleteAll(myItemList): QList<T*>を使用する場合、要素がポインタであるため、それらが指すメモリを手動で解放する必要があります。qDeleteAllはリスト内のすべてのポインタに対してdeleteを呼び出す便利な関数です。
  • anotherItemAのケース: anotherItemAitemA同じテキスト内容を持っていますが、異なるメモリアドレスに存在するため、myItemList.contains(anotherItemA)falseを返します。これは、ポインタのcontains()値の等価性ではなくアドレスの等価性をチェックするという重要な点を示しています。
  • myItemList.contains(itemA): このcontains()メソッドは、リストがitemAと同じメモリアドレスを持つポインタを含んでいるかどうかをチェックします。
  • QList<QStandardItem*>: QStandardItemへのポインタを格納するリストです。

例3: QListにカスタムクラスのオブジェクトが含まれるかチェックする(operator==のオーバーロード)

カスタムクラスのオブジェクトをQListに格納し、contains()を使用する際には、そのカスタムクラスにoperator==をオーバーロードする必要があります。

#include <QApplication>
#include <QList>
#include <QString>
#include <QDebug>

// カスタムクラスの定義
class MyData {
public:
    int id;
    QString name;

    MyData(int i, const QString& n) : id(i), name(n) {}

    // operator== をオーバーロードして、MyDataオブジェクトの「等価性」を定義する
    bool operator==(const MyData& other) const {
        return (id == other.id && name == other.name);
    }
};

int main(int argc, char *argv[]) {
    QApplication app(argc, argv);

    QList<MyData> dataList;
    dataList.append(MyData(1, "Alpha"));
    dataList.append(MyData(2, "Beta"));
    dataList.append(MyData(3, "Gamma"));

    qDebug() << "--- QList<MyData>::contains() の例 ---";

    // id:2, name:"Beta" のデータがリストに含まれるか?
    // MyData::operator== が呼び出される
    if (dataList.contains(MyData(2, "Beta"))) {
        qDebug() << "List contains MyData(2, 'Beta').";
    } else {
        qDebug() << "List does NOT contain MyData(2, 'Beta').";
    }

    // id:4, name:"Delta" のデータがリストに含まれるか?
    if (dataList.contains(MyData(4, "Delta"))) {
        qDebug() << "List contains MyData(4, 'Delta').";
    } else {
        qDebug() << "List does NOT contain MyData(4, 'Delta').";
    }

    return app.exec();
}
  • bool operator==(const MyData& other) const: このオーバーロードされた演算子がQList::contains()によって内部的に使用されます。これにより、2つのMyDataオブジェクトが「等しい」と見なされる条件(ここではidnameが両方とも一致すること)を定義できます。この演算子がない場合、コンパイルエラーになるか、予期しない動作をする可能性があります。
  • MyDataクラス: idnameを持つ単純なデータ構造です。


contains()メソッドは非常に便利ですが、特定の要件やパフォーマンスの考慮事項によっては、他のアプローチがより適切である場合があります。

QString::contains() の代替

文字列内の特定のサブ文字列の存在をチェックするQString::contains()の代替です。