| (同じ利用者による、間の6版が非表示) | |||
| 1行目: | 1行目: | ||
== 概要 == | == 概要 == | ||
Qtでは、<code>QRegularExpression</code>クラスを使用して正規表現を扱う。<br> | |||
これは現代的な正規表現エンジンを提供しており、Perl互換の正規表現構文をサポートしている。<br> | |||
<br> | |||
<u>Qt 5.11以前まで使用されていたQRegExpクラスは現在非推奨となっている。</u><br> | |||
<br> | |||
基本的な使用方法としては、パターンマッチングとテキスト置換が主な用途である。<br> | |||
<br> | |||
パターンマッチングでは、文字列が特定のパターンに一致するかどうかを確認する。<br> | |||
例えば、Eメールアドレスの検証やURLの抽出等に活用できる。<br> | |||
<br> | |||
<code>QRegularExpression</code>クラスには、<u>大文字小文字を区別するオプション</u>、<u>複数行モードの有効化</u>等、様々なオプションを設定することができる。<br> | |||
これらのオプションは、パターンマッチングの動作を細かく制御するのに役立つ。<br> | |||
<br> | |||
マッチング結果は<code>QRegularExpressionMatch</code>オブジェクトとして返されて、マッチした部分文字列や位置情報等の詳細な情報を取得できる。<br> | |||
また、グループキャプチャを使用する場合は、パターン内の特定の部分にマッチした文字列を個別に取得することも可能である。<br> | |||
<br> | |||
正規表現のパターンが正しく構築されているかどうかを確認する場合は、<code>isValid</code>メソッドで事前に確認できる。<br> | |||
これは、実行時エラーを防ぐために重要である。<br> | |||
<br> | |||
<u>パフォーマンスにおいて、同じパターンを複数回使用する場合は、QRegularExpressionオブジェクトを再利用することを推奨する。</u><br> | |||
これにより、パターンの再コンパイルを避けることができる。<br> | |||
<br><br> | <br><br> | ||
== QRegularExpressionクラス (推奨) == | == QRegularExpressionクラス (推奨) == | ||
==== QRegularExpressionクラスとは ==== | |||
QRegularExpressionクラスは、PCREライブラリを基盤としており、以下に示すようなメリットがある。<br> | QRegularExpressionクラスは、PCREライブラリを基盤としており、以下に示すようなメリットがある。<br> | ||
* パフォーマンスの向上 | * パフォーマンスの向上 | ||
| 15行目: | 37行目: | ||
移行を検討する場合は、既存のQRegExpクラスを使用したコードにおいて、新しい機能の実装時やコードのメンテナンス時に徐々にQRegularExpressionクラスへ移行することが推奨される。<br> | 移行を検討する場合は、既存のQRegExpクラスを使用したコードにおいて、新しい機能の実装時やコードのメンテナンス時に徐々にQRegularExpressionクラスへ移行することが推奨される。<br> | ||
<br> | <br> | ||
QRegularExpressionクラスで頻繁に使用するメソッドを以下に示す。<br> | |||
* <code>hasMatch</code>メソッド | |||
*: パターンがテキストにマッチしたかどうかをbool値で返す。 | |||
*: trueの場合はマッチが成功、falseの場合は失敗を意味する。 | |||
* <code>captured</code>メソッド | |||
*: マッチした部分文字列や、括弧でグループ化された部分を取得する。 | |||
*: 引数無しの場合は完全なマッチを返す。 | |||
*: 数値を指定する場合、その番号のキャプチャグループを返す。 | |||
*: 文字列を指定する場合、その名前のキャプチャグループを返す。 | |||
<br> | |||
<u>※注意</u><br> | |||
* パターンの最適化 | |||
*: 頻繁に使用する正規表現パターンは、オブジェクトとして保持して再利用することにより、パフォーマンスを向上させることができる。 | |||
* エラー処理 | |||
*: isValidメソッドを使用して、正規表現パターンの妥当性を確認することが推奨される。 | |||
<br> | |||
==== QRegularExpressionクラスの使用例 ==== | |||
<syntaxhighlight lang="c++"> | |||
#include <QRegularExpression> | |||
#include <QDebug> | |||
class RegexExamples | |||
{ | |||
public: | |||
// メールアドレスの検証 | |||
static bool validateEmail(const QString& email) | |||
{ | |||
// CaseInsensitiveOptionオプションは、大文字と小文字を区別せずにマッチングを行う | |||
QRegularExpression re("^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$", QRegularExpression::CaseInsensitiveOption); | |||
QRegularExpressionMatch match = re.match(email); | |||
return match.hasMatch(); | |||
} | |||
// 電話番号からハイフンを除去 | |||
static QString normalizePhoneNumber(const QString& phone) | |||
{ | |||
QRegularExpression re("[^0-9]"); | |||
return phone.replace(re, ""); | |||
} | |||
// HTMLタグの抽出 | |||
static void extractHtmlTags(const QString& html) | |||
{ | |||
QRegularExpression re("<([a-zA-Z0-9]+)[^>]*>"); | |||
QRegularExpressionMatchIterator i = re.globalMatch(html); | |||
while (i.hasNext()) { | |||
QRegularExpressionMatch match = i.next(); | |||
qDebug() << "Found tag:" << match.captured(1); | |||
} | |||
} | |||
// 日付形式の変換 (YYYY/MM/DD -> MM-DD-YYYY) | |||
static QString convertDateFormat(const QString& date) | |||
{ | |||
QRegularExpression re("(\\d{4})/(\\d{2})/(\\d{2})"); | |||
QRegularExpressionMatch match = re.match(date); | |||
if (match.hasMatch()) { | |||
return QString("%1-%2-%3").arg(match.captured(2)) | |||
.arg(match.captured(3)) | |||
.arg(match.captured(1)); | |||
} | |||
return date; | |||
} | |||
// 文字列内の数値を抽出して合計を計算 | |||
static int sumNumbersInText(const QString& text) | |||
{ | |||
QRegularExpression re("\\d+"); | |||
QRegularExpressionMatchIterator i = re.globalMatch(text); | |||
int sum = 0; | |||
while (i.hasNext()) { | |||
QRegularExpressionMatch match = i.next(); | |||
sum += match.captured().toInt(); | |||
} | |||
return sum; | |||
} | |||
// URLからクエリパラメータを抽出 | |||
static QMap<QString, QString> parseQueryParameters(const QString& url) | |||
{ | |||
QMap<QString, QString> params; | |||
QRegularExpression re("([^=&?]+)=([^&]*)"); | |||
QRegularExpressionMatchIterator i = re.globalMatch(url); | |||
while (i.hasNext()) { | |||
QRegularExpressionMatch match = i.next(); | |||
params[match.captured(1)] = match.captured(2); | |||
} | |||
return params; | |||
} | |||
// コードからコメントを抽出 | |||
static void extractComments(const QString& code) | |||
{ | |||
// 単一行コメント | |||
// MultilineOptionオプションは、複数行のテキストで、行ごとに独立してパターンマッチングを行う | |||
// ^ (行頭) と $ (行末) が各行に対して機能する | |||
QRegularExpression singleLine("//(.*)$", QRegularExpression::MultilineOption); | |||
// 複数行コメント | |||
QRegularExpression multiLine("/\\*([^*]|\\*(?!/))*\\*/"); | |||
auto processMatch = [](const QRegularExpressionMatch& match) { | |||
QString comment = match.captured(0).trimmed(); | |||
qDebug() << "Found comment:" << comment; | |||
}; | |||
// globalMatchメソッドを使用して、テキスト内の全てのマッチを処理 | |||
QRegularExpressionMatchIterator i1 = singleLine.globalMatch(code); | |||
while (i1.hasNext()) { | |||
processMatch(i1.next()); | |||
} | |||
QRegularExpressionMatchIterator i2 = multiLine.globalMatch(code); | |||
while (i2.hasNext()) { | |||
processMatch(i2.next()); | |||
} | |||
} | |||
}; | |||
</syntaxhighlight> | |||
<br> | |||
<syntaxhighlight lang="c++"> | |||
// 使用例 | |||
#include <QDebug> | |||
qDebug() << "Email validation: " << RegexExamples::validateEmail("test@example.com"); | |||
qDebug() << "Normalized phone: " << RegexExamples::normalizePhoneNumber("123-456-7890"); | |||
QString html = "<div>content</div><p>paragraph</p>"; | |||
RegexExamples::extractHtmlTags(html); | |||
qDebug() << "Converted date: " << RegexExamples::convertDateFormat("2024/03/25"); | |||
QString text = "Values: 10, 20, 30"; | |||
qDebug() << "Sum of numbers: " << RegexExamples::sumNumbersInText(text); | |||
QString url = "https://example.com?name=John&age=25"; | |||
QMap<QString, QString> params = RegexExamples::parseQueryParameters(url); | |||
qDebug() << "URL parameters:" << params; | |||
QString code = "// This is a comment\nint x = 5;\n/* Multi\nline\ncomment */"; | |||
RegexExamples::extractComments(code); | |||
</syntaxhighlight> | |||
<br> | |||
==== CaseInsensitiveOptionオプション ==== | |||
<syntaxhighlight lang="c++"> | |||
#include <QRegularExpression> | |||
#include <QDebug> | |||
QRegularExpression reCase("hello", QRegularExpression::CaseInsensitiveOption); | |||
QRegularExpressionMatch matchCase = reCase.match("HELLO world"); | |||
qDebug() << "Case insensitive match: " << matchCase.hasMatch(); // true | |||
</syntaxhighlight> | |||
<br> | |||
==== MultilineOptionオプション ==== | |||
<syntaxhighlight lang="c++"> | |||
#include <QRegularExpression> | |||
#include <QDebug> | |||
QString multilineText = "Line1\nLine2\nLine3"; | |||
QRegularExpression reMulti("^Line", QRegularExpression::MultilineOption); | |||
QRegularExpressionMatchIterator i = reMulti.globalMatch(multilineText); | |||
while (i.hasNext()) { | |||
QRegularExpressionMatch match = i.next(); | |||
qDebug() << "Found at position: " << match.capturedStart(); | |||
} | |||
</syntaxhighlight> | |||
<br> | |||
==== キャプチャグループ (数値指定) ==== | |||
<syntaxhighlight lang="c++"> | |||
#include <QRegularExpression> | |||
#include <QDebug> | |||
QRegularExpression reGroup("(\\w+)=(\\d+)"); | |||
QRegularExpressionMatch matchGroup = reGroup.match("age=25"); | |||
if (matchGroup.hasMatch()) { | |||
qDebug() << "Full match: " << matchGroup.captured(0); // "age=25" | |||
qDebug() << "First group: " << matchGroup.captured(1); // "age" | |||
qDebug() << "Second group: " << matchGroup.captured(2); // "25" | |||
} | |||
</syntaxhighlight> | |||
<br> | |||
==== 名前付きキャプチャグループ ==== | |||
<syntaxhighlight lang="c++"> | |||
#include <QRegularExpression> | |||
#include <QDebug> | |||
QRegularExpression reNamed("(?<key>\\w+)=(?<value>\\d+)"); | |||
QRegularExpressionMatch matchNamed = reNamed.match("count=42"); | |||
if (matchNamed.hasMatch()) { | |||
qDebug() << "Key: " << matchNamed.captured("key"); // "count" | |||
qDebug() << "Value: " << matchNamed.captured("value"); // "42" | |||
} | |||
</syntaxhighlight> | |||
<br> | |||
==== マッチ位置の取得 ==== | |||
<syntaxhighlight lang="c++"> | |||
#include <QRegularExpression> | |||
#include <QDebug> | |||
QString text = "Hello, my email is test@example.com and phone is 123-456-7890"; | |||
// メールアドレスのパターン | |||
QRegularExpression emailRegex(R"(\b[\w\.-]+@[\w\.-]+\.\w+\b)"); | |||
// メールアドレスのマッチング | |||
QRegularExpressionMatch emailMatch = emailRegex.match(text); | |||
if (emailMatch.hasMatch()) { | |||
qDebug() << "Match text: " << emailMatch.captured(0); | |||
qDebug() << "Start position: " << emailMatch.capturedStart(); | |||
qDebug() << "Length: " << emailMatch.capturedLength(); | |||
qDebug() << "End position: " << emailMatch.capturedStart() + emailMatch.capturedLength(); | |||
} | |||
// 電話番号のパターン | |||
QRegularExpression phoneRegex(R"(\d{3}-\d{3}-\d{4})"); | |||
// 電話番号のマッチング | |||
QRegularExpressionMatch phoneMatch = phoneRegex.match(text); | |||
if (phoneMatch.hasMatch()) { | |||
qDebug() << "Match text: " << phoneMatch.captured(0); | |||
qDebug() << "Start position: " << phoneMatch.capturedStart(); | |||
qDebug() << "Length: " << phoneMatch.capturedLength(); | |||
qDebug() << "End position: " << phoneMatch.capturedStart() + phoneMatch.capturedLength(); | |||
} | |||
</syntaxhighlight> | |||
<br><br> | <br><br> | ||
== QRegExpクラス (非推奨) == | == QRegExpクラス (非推奨) == | ||
QRegExpクラスには技術的な限界があり、PCRE (Perl Compatible Regular Expressions) との完全な互換性がなく、現代的な正規表現機能の一部をサポートしていない。<br> | |||
例えば、先読み・後読みのような高度なパターンマッチング機能が制限されている。<br> | 例えば、先読み・後読みのような高度なパターンマッチング機能が制限されている。<br> | ||
<br> | |||
<u>Qt 5.12以降では、QRegExpクラスの代わりにQRegularExpressionクラスの使用が推奨されている。</u><br> | |||
<br> | |||
<u>※注意</u><br> | |||
<u>パターンに特殊文字を含める場合は、適切にエスケープする必要がある。</u><br> | |||
<u>パフォーマンスが重要な場合は、正規表現パターンを事前にコンパイルしておくことを推奨する。</u><br> | |||
<br> | <br> | ||
==== 基本的なマッチング ==== | ==== 基本的なマッチング ==== | ||
<syntaxhighlight lang="c++"> | <syntaxhighlight lang="c++"> | ||
// 単純な文字列パターンのマッチング | |||
#include <QRegExp> | #include <QRegExp> | ||
#include <QDebug> | #include <QDebug> | ||
| 35行目: | 294行目: | ||
==== メタキャラクターを使用したパターン ==== | ==== メタキャラクターを使用したパターン ==== | ||
<syntaxhighlight lang="c++"> | <syntaxhighlight lang="c++"> | ||
// \d (数字) や \w (単語文字) 等の特殊文字の使用 | |||
#include <QRegExp> | #include <QRegExp> | ||
#include <QDebug> | #include <QDebug> | ||
| 44行目: | 305行目: | ||
==== 選択パターン ==== | ==== 選択パターン ==== | ||
<syntaxhighlight lang="c++"> | <syntaxhighlight lang="c++"> | ||
// | (パイプ) を使用した複数パターンの選択 | |||
#include <QRegExp> | #include <QRegExp> | ||
#include <QDebug> | #include <QDebug> | ||
| 54行目: | 317行目: | ||
==== グループ化とキャプチャ ==== | ==== グループ化とキャプチャ ==== | ||
<syntaxhighlight lang="c++"> | <syntaxhighlight lang="c++"> | ||
// ()を使用したグループ化と、capメソッドによるキャプチャ内容の取得 | |||
#include <QRegExp> | #include <QRegExp> | ||
#include <QDebug> | #include <QDebug> | ||
| 68行目: | 333行目: | ||
==== 量指定子の使用 ==== | ==== 量指定子の使用 ==== | ||
<syntaxhighlight lang="c++"> | <syntaxhighlight lang="c++"> | ||
// {n,m}形式での繰り返し回数の指定 | |||
#include <QRegExp> | #include <QRegExp> | ||
#include <QDebug> | #include <QDebug> | ||
| 77行目: | 344行目: | ||
==== 文字クラス ==== | ==== 文字クラス ==== | ||
<syntaxhighlight lang="c++"> | <syntaxhighlight lang="c++"> | ||
// []を使用した文字の範囲指定 | |||
#include <QRegExp> | #include <QRegExp> | ||
#include <QDebug> | #include <QDebug> | ||
| 86行目: | 355行目: | ||
==== テキスト置換 ==== | ==== テキスト置換 ==== | ||
<syntaxhighlight lang="c++"> | <syntaxhighlight lang="c++"> | ||
// replaceメソッドを使用したパターンマッチング置換 | |||
#include <QRegExp> | #include <QRegExp> | ||
#include <QDebug> | #include <QDebug> | ||
| 97行目: | 368行目: | ||
==== 否定文字クラス ==== | ==== 否定文字クラス ==== | ||
<syntaxhighlight lang="c++"> | <syntaxhighlight lang="c++"> | ||
// [^...]形式での否定パターン | |||
#include <QRegExp> | #include <QRegExp> | ||
#include <QDebug> | #include <QDebug> | ||
| 106行目: | 379行目: | ||
==== 位置指定 ==== | ==== 位置指定 ==== | ||
<syntaxhighlight lang="c++"> | <syntaxhighlight lang="c++"> | ||
// ^ (行頭) や $ (行末) 等のアンカー | |||
#include <QRegExp> | #include <QRegExp> | ||
#include <QDebug> | #include <QDebug> | ||
| 115行目: | 390行目: | ||
==== グリーディマッチとノングリーディマッチ ==== | ==== グリーディマッチとノングリーディマッチ ==== | ||
<syntaxhighlight lang="c++"> | <syntaxhighlight lang="c++"> | ||
// .と.?の違いによる最長一致と最短一致の制御 | |||
#include <QRegExp> | #include <QRegExp> | ||
#include <QDebug> | #include <QDebug> | ||
| 133行目: | 410行目: | ||
==== ワイルドカードモード ==== | ==== ワイルドカードモード ==== | ||
<syntaxhighlight lang="c++"> | <syntaxhighlight lang="c++"> | ||
// ファイル名パターンマッチング等に使用する簡易的なパターン | |||
#include <QRegExp> | #include <QRegExp> | ||
#include <QDebug> | #include <QDebug> | ||