「Qtの基礎 - 文字列」の版間の差分

提供:MochiuWiki - SUSE, Electronic Circuit, PCB
ナビゲーションに移動 検索に移動
547行目: 547行目:
==== 重複の削除 ====
==== 重複の削除 ====
* 推奨される方法
* 推奨される方法
*: <code>QList<T>(set.begin(), set.end())とQSet<T>(list.begin(), list.end())</code>を使用することが推奨される。<br>
*: <code>QList<T>(set.begin(), set.end())</code>と<code>QSet<T>(list.begin(), list.end())</code>を使用することが推奨される。<br>
  <syntaxhighlight lang="c++">
  <syntaxhighlight lang="c++">
  #include <QStringList>
  #include <QStringList>

2024年7月27日 (土) 03:47時点における版

概要



数値を文字列に変換する

QString::number()を使用して、数値を文字列に変換する。

少数を変換する場合、第2引数にeまたはEを指定すると指数表記、fを指定すると少数表記になる。
この時、第3引数の数値は、小数点以下の桁数となる。

第2引数にgまたはGを指定すると、指数表記と少数表記のうち、より簡潔に表現できる方で変換される。
この時、第3引数の数値は、有効桁数となる。

第2引数の詳細は、Qtの公式Webサイトを参照すること。

 int i = 10;

 qDebug() << QString::number(i);                  // 10進数として文字列化
 qDebug() << QString::number(i,  8);              //  8進数として文字列化
 qDebug() << QString::number(i, 16);              // 16進数として文字列化(アルファベット小文字)
 qDebug() << QString::number(i, 16).toUpper();    // 16進数として文字列化(アルファベット大文字)
 
 double d = 12.3456789;
 qDebug() << QString::number(d, 'e', 1);          // 浮動小数12.3456789を小数点以下1桁で指数表記
 qDebug() << QString::number(d, 'e', 7);          // 浮動小数12.3456789を小数点以下7桁で指数表記
 qDebug() << QString::number(d, 'f', 1);          // 浮動小数12.3456789を小数点以下1桁で小数表記  --> 12.3
 qDebug() << QString::number(d, 'f', 5);          // 浮動小数12.3456789を小数点以下7桁で小数表記  --> 12.34568
 
 qDebug() << QString::number(0.0000001, 'g', 7);  // 浮動小数0.0000001を有効桁数7桁で簡潔表記
 qDebug() << QString::number(1.2345678, 'g', 7);  // 浮動小数1.2345678を有効桁数7桁で簡潔表記
 
 qDebug() << QString((int)'A' + 2);               // 16進数 0x0Cが文字Cに変換される



文字列を数値に変換する

 QString numStr = "1234";
 
 int i = numStr.toInt();	// i=1234
 long l = numStr.toLong();	// l=1234
 double d = numStr.toDouble();	// d=1234



文字列の長さや数を取得する

 QString txtStr = "ABC123:def12 6";
 
 int sz = txtStr.length();       // 空白を含む文字数                sz=14
 int ix = txtStr.indexOf("12");  // 指定文字列を最初に見つけた位置  ix=3
 int cnt = txtStr.count("12");   // 指定文字列の個数                cnt=2
 QString str = txtStr.at(1);     // 指定位置の文字                  str="B"


※注意
lengthは0x00も1文字として数える。


文字列の確認

 QString txtStr = "ABC123:def126 ";
 
 bool bl = txtStr.contains("F12");                       // 指定文字を含むか      bl=false
 bool bl = txtStr.contains("F12", Qt::CaseInsensitive);  // 指定文字を含むか      bl=true
 bool bl = txtStr.startsWith("A");                       // 指定文字から始まるか  bl=true
 bool bl = txtStr.endsWith("6");                         // 指定文字で終わるか    bl=false(最後は空白)
 
 // isNullメソッドとisEmptyメソッドは異なる
 QString txtStr2 = "";
 
 bool bl = txtStr.isEmpty();  // 空か    bl=true
 bool bl = txtStr.isNull();   // NULLか	 bl=false


※注意
CaseInsensitiveを指定する場合、大文字・小文字の区別を無視する。
startsWithメソッドとendsWithメソッドも、CaseInsensitiveを指定することができる。


基本的な文字列操作

 QString txtStr = "ABC123:def126 ";
 
 QString str = txtStr.mid(1, 3);    // 指定位置から指定文字数を切り出す  str="BC1"
 QString str = txtStr.mid(3);       // 指定位置以降の文字列を切り出す   str="123:def126 "
 QString str = txtStr.left(1);      // 先頭から指定文字数を切り出す     str="A"
 QString str = txtStr.right(2);     // 末尾から指定文字数を切り出す     str="6 "
 QString str = txtStr.toLower();    // アルファベット小文字に変換する     str="abc123:def126 "
 QString str = txtStr.toUpper();    // アルファベット大文字に変換する     str="ABC123:DEF126 "
 QString str = txtStr.repeated(2);  // 指定回数だけ繰り返す           str="ABC123:def126 ABC123:def126 "


以下の例では、元の文字列を書き換えるため、使用する場合は注意が必要である。

 QString txtStr = "ABC123:def126 ";
 
 txtStr.replace(3, 2, "xy");        // 指定位置から指定文字数の置き換える  txtStr="ABCxy3:def126 "
 txtStr.chop(2);                    // 末尾の指定文字数を削除する          txtStr="ABCxy3:def12"
 txtStr.insert(1, QString("and"));  // 指定位置の前に挿入する              txtStr="AandBCxy3:def12"
 txtStr.fill('X', 4);               // 文字を指定数並べる                  txtStr="XXXX"
 txtStr.setNum(2.5);                // 数値を文字列に変換する              txtStr="2.5"



文字列の右詰め

 QString txtStr = "12345";
 
 QString str = txtStr.rightJustified(8, '0');               // str="00012345"
 QString str = txtStr.rightJustified(8, '.');               // str="...12345"
 QString str = txtStr.rightJustified(3, '.', true);         // str="123"
 QString str = txtStr.rightJustified(3, '.', false);        // str="12345"
 QString str = QString::number(98).rightJustified(4, '0');  // str="0098"


※注意
rightJustifiedメソッドの第3引数の初期値は、falseである。trueを指定すると指定桁数に切り詰める。


空白の切り詰め

simplifiedメソッドは、空白・タブ・改行をまとめて1つの空白に置き換える。この時、先頭と末尾は削られる。
trimmedメソッドは、先頭と末尾の空白・タブ・改行を取り除く。

 QString txtStr = "\t AB CD\n EF GH\tIJ\n\nKL \n";
 
 QString str = txtStr.simplified();	str="AB CD EF GH IJ KL"
 QString str = txtStr.trimmed();	str="AB CD\n EF GH\tIJ\n\nKL"



パディング

以下の例では、1~1000までの整数を0001、0002、0003、...、1000という文字列にパディングしている。

第3引数(初期値 : false)の違いは、第1引数で指定した桁数を超える場合、後ろを切る捨てるか否かの設定である。

 for(int i = 1; i <= 1000; i++)
 {
    qDebug() << QString::number(i).rightJustified(4, '0');
 }
 
 for(int i = 1; i <= 1000; i++)
 {
    qDebug() << QString::number(i).rightJustified(4, '0', true);
 }


また、rightJustifiedメソッドは、文字列の先頭を空白で埋めるなどもできる。

 QStringList list = {"a", "aa", "aaa", "aaaa", "aaaaa"};
  
 for(QString str : list)
 {
    qDebug() << str.rightJustified(5, ' ');
 }



文字列の分割

以下の例では、文字列を区切り文字で分割して、文字列リスト(QStringList)に代入している。

 QString txtStr = "ABC123:def12 ";
 QStringList list = txtStr.split(":");  // :(コロン)で分割する
 
 QString str = list[0];                 // "ABC123"
 QString str = list[1];                 // "def12 "


以下の例では、ループで文字列リストを処理している。上記と同様の結果になる。

 QString txtStr = "ABC123:def12 ";
 QStringList list = txtStr.split(":");  // :(コロン)で分割する
 
 for(int i = 0; i < list.count(); i++)
 {
    QString str = list.at(i);  // list[i]でも同じ
 }
 
 foreach(QString word, list)
 {
    QString str = word;
 }



文字列の整形

arg%を使用して、文字列を整形できる。

 QString str = QString("座標=(%1, %2) サイズ=%3x%4 テキスト=%5").arg(10).arg(20).arg(240).arg(120).arg("メッセージ");
 // str="座標=(10, 20) サイズ=240x120 テキスト=メッセージ"


また、printfのように文字列を整形することもできる。

 QString sDt="ABC";
 
 QString str;
 
 // Qt 5.7以前
 str.sprintf("%02d:%02d, %cクラス, 0x%04x, (%4.2lf), (%-3d), (%5s), (%.2s)", 9, 2, 'S', 255, 3.1415, 7, qPrintable(sDt), qPrintable(sDt));
 // str="09:02, Sクラス, 0x00ff, (3.14), (7  ), (  ABC), (AB)"
 
 // Qt 5.7以降
 QString str = QString::asprintf("%02d:%02d, %cクラス, 0x%04x, (%4.2lf), (%-3d), (%5s), (%.2s)", 9, 2, 'S', 255, 3.1415, 7, qPrintable(sDt), qPrintable(sDt));
 // str="09:02, Sクラス, 0x00ff, (3.14), (7  ), (  ABC), (AB)"


※注意
半角英数の場合はqPrintable関数でも表示できるが、全角文字の場合はQStringクラスのtoUtf8().constData()を使用しないと文字化けする。
また、Qt 5.7以降では、以下のように、QString::asprintfメソッドが使用できる。

 QString str = QString::asprintf("フォーマット", データの並び);



文字列の先頭に挿入

先頭に文字列を挿入する場合、QStringクラスのprependメソッドを使用する。
このメソッドは、呼び出された文字列の先頭に指定した文字列を挿入する。

prependメソッドは呼び出し元のQStringオブジェクト自体を変更するため、新たに変数を定義する必要はない。

 QString str = "piyo fuga";  // 出力 : "piyo fuga"
 str.prepend("hoge ");       // 出力 : "hoge piyo fuga"



特定の文字列の削除

以下の例では、<table>タグから</table>タグまでの文字列を正規表現を使用して削除している。

QRegularExpression::DotMatchesEverythingOptionオプションは、"."を使用することにより改行文字にもマッチするようにしている。
これは、<table>タグが複数行に跨っている場合でも対応するためである。

 QString description = R"(<div>Some content before the table <table><tr><td>Cell content</td></tr></table> and some content after.</div>)";
 
 // "<table>"から"</table>"までの内容を含む正規表現パターン
 QRegularExpression tableTagPattern("<table.*>.*</table>", QRegularExpression::DotMatchesEverythingOption);
 
 // 該当するパターンを全て削除
 description.remove(tableTagPattern);


 QString description = R"(<div>Some content before the table <table><tr><td>Cell content</td></tr></table> and some content after.</div>)";
 
 // "<table>"から"</table>"までの内容を含む正規表現パターン
 QRegularExpression tableTagPattern("<table.*>.*</table>", QRegularExpression::DotMatchesEverythingOption);
 
 // 該当するパターンを全て削除
 description.remove(tableTagPattern);



改行文字の挿入

QString型に改行文字を挿入することができる。

プラットフォームに依存しない改行文字をQString型に格納する方法を、以下に示す。

  • QStringLiteralを使用する場合
 QString a = QStringLiteral("\n");


  • QLatin1Charを使用する場合
 QString a = QLatin1Char('\n');


  • QCharを使用する場合
 QString a = QChar::LineFeed;


また、Qt::endlを使用する場合は、QTextStreamクラスと組み合わせてQString型に挿入することもできる。

 QString result;
 QTextStream stream(&result);
 stream << "First line" << Qt::endl << "Second line";  // resultに改行を含む文字列が格納される



QString型からchar型またはstd::string型へ変換

QString型はUTF-16でエンコードされているのに対して、char型またはstd::string型はどの種類のエンコーディングでもよいことに注意する。

以下の例では、QString型(UTF-16)からchar型(UTF-8)またはstd::string型(UTF-8)へ変換している。

 QString strUTF16 = "Sample";
 
 // LinuxまたはMacOSにおいて、UTF-8を使用している場合
 std::string strUTF8 = strUTF16.toUtf8().constData();
 
 // toStdStringメソッドは変換される文字列がUTF-8でエンコードされていることを前提としている
 // QStringが別のエンコーディング (例: UTF-16) を使用している場合、正しく変換されない可能性があるため注意
 std::string strUTF8 = strUTF16.toStdString();
 
 // Windowsにおいて、UTF-8を使用している場合
 std::string strCurrentLocale = strUTF16.toLocal8Bit().constData();


また、qPrintable(const QString &str)マクロも存在しており、これは、<QString型のオブジェクト>.toLocal8Bit().constData()に展開される。


char*型からQString型へ変換

char*型からQString型への変換は、簡単に行うことができる。
ただし、変換方法は、元のchar*型がどのエンコーディングで保存されているかにより異なることに注意する。

  • UTF-8エンコーディングの場合
 char *pstr   = "Hello, World!";
 QString qstr = QString::fromUtf8(pstr);


  • システムのローカルエンコーディングの場合
 char *pstr   = "Hello, World!";
 QString qstr = QString::fromLocal8Bit(pstr);


  • Latin-1 (ISO 8859-1) エンコーディングの場合
 char *pstr   = "Hello, World!";
 QString qstr = QString::fromLatin1(pstr);


  • エンコーディングが不明な場合や単純なASCIIの場合
 char *pstr   = "Hello, World!";
 QString qstr = QString(pstr);


また、char*型の長さが既知の場合は、以下に示すようにオーバーロードされたバージョンを使用することができる。

 char *pstr   = "Hello, World!";
 int length   = 13;  // "Hello, World!"の長さ
 QString qstr = QString::fromUtf8(pstr, length);


※注意

  • 可能な限り、QString::fromUtf8()QString::fromLocal8Bit()を使用することを推奨する。
    これらのメソッドは、文字エンコーディングを正しく扱うことができる。
  • QString(char*)コンストラクタを使用する場合、QtはデフォルトでLatin-1エンコーディングを仮定する。
    これは、非ASCII文字を含む文字列で問題を引き起こす可能性がある。
  • char*型がnull終端されていることを確認する必要がある。
    そうでない場合、長さを明示的に指定する必要がある。
  • メモリ管理に注意すること。
    動的にchar*型が割り当てられている場合、QString型に変換した後、元のchar*型が不要になった場合は適切に解放する必要がある。



QString型からQByteArray型へ変換

 QString    strData   = "文字列";
 QByteArray byaryData = strData.toUtf8();
 
 // または
 
 #include <QTextCodec>
 
 QString strData = "文字列";
 QTextCodec *codec = QTextCodec::codecForName("UTF-8");
 QByteArray byaryData = codec->fromUnicode(strData);



QByteArray型からQString型へ変換

 QByteArray byaryData = file.readAll();
 QString    strData   = QString::fromUtf8(byaryData);



文字エンコード

Shift-JISからUTF-8へ変換

QTextCodecクラスは、様々な文字エンコード間での文字列の変換をサポートしている。

以下の例では、QStringクラスに格納されている文字列がShift-JISであると仮定しているが、実際にはQStringクラスは内部的にUTF-16を使用している。
したがって、本来変換が必要なものは、外部から入力されるShift-JISでエンコードされたデータ (例: ファイルやネットワーク経由で受信したデータ) を扱う場合である。

そのため、実務等で使用する場合は、外部データをQByteArrayクラスで受け取り、それをQStringクラスに変換する時にエンコーディングを考慮する必要がある。

 #include <QTextCodec>
 
 // Shift-JISでエンコードされた文字列
 QString SJISText = QStringLiteral("こんにちは");  // Shift-JISでエンコードされた文字列
 
 // Shift-JISのコーデックを取得
 QTextCodec *codec = QTextCodec::codecForName("Shift-JIS");
 
 // Shift-JISのQByteArrayに変換
 QByteArray shiftJISBytes = codec->fromUnicode(SJISText);
 
 // UTF-8の文字列に変換
 QString utf8String = QString::fromUtf8(shiftJISBytes);
 // または
 QString utf8String = codec->toUnicode(shiftJISBytes);


UTF-8からShift-JISへ変換

以下の例では、QTextCodec::codecForName("Shift-JIS")でShift-JISのQTextCodecオブジェクトを取得して、
fromUnicodeメソッドを使用してUTF-8エンコードされたQStringクラスをShift-JISエンコードされたQByteArrayクラスに変換している。

QByteArrayクラスはバイナリデータを表すため、この変換により得られたバイト配列をファイルやネットワーク経由で送信する時にShift-JISとして扱うことができる。

ただし、変換プロセス中に文字の損失や変換できない文字がある場合、QTextCodecクラスはデフォルトでその文字を?に置換、あるいは、無視する設定がある。
変換の精度を高めるためには、QTextCodec::ConverterOptionsを使用して、変換の挙動を細かく制御することが重要である。

 #include <QTextCodec>
 
 // UTF-8でエンコードされた文字列
 QString utf8Text = QStringLiteral("こんにちは");
 
 // Shift-JISのコーデックを取得
 QTextCodec *codec = QTextCodec::codecForName("Shift-JIS");
 
 // UTF-8のQStringをShift-JISのQByteArrayに変換
 QByteArray shiftJISBytes = codec->fromUnicode(utf8Text);


UTF-8からEUC-JPへ変換

 #include <QTextCodec>
 
 // UTF-8でエンコードされた文字列
 QString utf8Text = QStringLiteral("こんにちは");
 
 // EUC-JPのコーデックを取得
 QTextCodec *codec = QTextCodec::codecForName("EUC-JP");
 
 // UTF-8の文字列をEUC-JPのQByteArrayに変換
 QByteArray eucJPBytes = codec->fromUnicode(utf8String);
 
 // EUC-JPエンコードされたデータを16進数で表示
 std::cout << eucJPText.toHex() << std::endl;



その他の変換

以下の例では、数値が整数の場合はそのままQStringクラスへ変換、数値に小数点が含まれている場合は小数点以下を除去してQStringクラスへ変換する関数である。

QVariantクラスは、多くの異なるデータ型を格納することができる。
この柔軟性により、整数型だけでなく浮動小数点型等の様々な数値型をこの関数に渡すことが可能となる。

 #include <QCoreApplication>
 #include <QVariant>
 #include <cmath>
 
 QString convertNumberToString(const QVariant &value)
 {
    if (value.type() == QVariant::Int || value.type() == QVariant::LongLong) {
       // 数値が整数の場合
       return value.toString();
 
       // 戻り値が整数型の場合
       //return value.toInt();
    }
    else if (value.type() == QVariant::Double) {
       // 数値が浮動小数点の場合
       double number = value.toDouble();
 
       // 戻り値がQStringクラスの場合、小数点以下を切り捨て
       double intPart;
       std::modf(number, &intPart);
       return QString::number(intPart, 'f', 0);  // 'f'フォーマットと0桁で小数点以下を除去
 
       // 戻り値が整数型の場合
       //return static_cast<int>(std::floor(number));
    }
 
    // その他の型の場合は空のQStringを返す
    return QString();
 
    // 戻り値が整数型の場合、その他の型の場合は0を返す
    //return 0;
 }
 
 int main(int argc, char *argv[])
 {
    QCoreApplication app(argc, argv);

    // 整数を渡す例
    QVariant intValue = 42;
    QString intResult = convertNumberToString(intValue);
    std::cout << QString("整数の結果 : %1").arg(intResult).toStdString() << std::endl;  // "42"と表示
 
    // 浮動小数点数を渡す例
    QVariant floatValue = 42.56;
    QString floatResult = convertNumberToString(floatValue);
    std::cout << QString("浮動小数点数の結果(小数点以下除去) : %1").arg(floatResult).toStdString() << std::endl;  // "42"と表示
 
    return app.exec();
 }



QStringListクラス

特定の要素の確認

QStringListクラスの要素群の中に特定の要素が存在する場合、containsメソッドを使用する。

 QStringList list;
 list << "apple" << "banana" << "cherry";
 
 // 特定の要素が存在するかどうかを確認
 bool exists = list.contains("hoge");
 
 if (exists) {
    qDebug() << "要素\"hoge\"が存在します";
 }
 else {
    qDebug() << "要素\"hoge\"は存在しません";
 }


特定の要素の削除

QStringListクラス内の要素群から特定の要素を削除する。

QStringListクラスは、QList<QString>のtypedefであるため、QListクラスに変換して類似の処理を行うことが可能である。

※注意
QStringListやその他のQtのコンテナクラスにおいて、std::remove_ifを直接使用することは推奨されていない。
これは、QtのコンテナがC++ STLコンテナと異なる内部実装を持っているためである。

以下の例では、QMutableListIteratorクラスを使用して、QStringListから特定の要素 (この場合は"hoge") を削除している。

 QStringList list = {"foo", "bar", "hoge", "baz"};
 QMutableListIterator<QString> i(list);
 while (i.hasNext()) {
    if (i.next() == "hoge") {
       i.remove();
    }
 }


QtのコンテナクラスはC++ STLと完全な互換性は無いが、QListクラスに変換した後であればstd::remove_ifメソッドを使用することができる。
以下の例では、std::remove_ifメソッドやQList::eraseメソッドと組み合わせて、特定の要素 (この場合は"hoge") を削除している。

 // QStringListからQListへ変換
 QStringList list = {"foo", "bar", "hoge", "baz"};
 QList<QString> qlist = list;
 
 // 特定の要素を削除するラムダ式 (この場合は、要素"hoge"を削除)
 auto newEnd = std::remove_if(qlist.begin(), qlist.end(), [](const QString &value) {
    return value == "hoge";
 });
 
 // リストから要素を削除
 qlist.erase(newEnd, qlist.end());
 
 // QListからQStringListへ変換
 list = QStringList::fromList(qlist);


重複の削除

  • 推奨される方法
    QList<T>(set.begin(), set.end())QSet<T>(list.begin(), list.end())を使用することが推奨される。
 #include <QStringList>
 #include <QSet>
 
 QStringList originalList = {"redhat", "redhat", "suse", "debian", "suse", "redhat"};
 
 QSet<QString> uniqueSet(originalList.begin(), originalList.end());
 QStringList uniqueList(uniqueSet.begin(), uniqueSet.end());
 
 // 出力: ("redhat", "suse", "debian")
 qDebug() << "Unique List:" << uniqueList;


  • 非推奨の方法
    QStringList::fromSet()QStringList::toSet()は非推奨である。
 #include <QStringList>
 #include <QSet>
 
 QStringList originalList = {"redhat", "redhat", "suse", "debian", "suse", "redhat"};
 
 QStringList uniqueList = QStringList::fromSet(originalList.toSet());
 
 // 出力: ("redhat", "suse", "debian")
 qDebug() << "Unique List:" << uniqueList;