C ++での正規表現の基本

Regular Expression Basics C



引用符で囲まれた次の文を検討してください。

「これが私の男です。」

この文字列はコンピュータ内にある可能性があり、ユーザーはそれがmanという単語を持っているかどうかを知りたい場合があります。男性という単語が含まれている場合は、男性という単語を女性に変更することをお勧めします。文字列が次のようになるようにします。







「これが私の女性です。」

コンピュータユーザーからのこれらのような他の多くの欲求があります。複雑なものもあります。正規表現(省略形、regex)は、コンピューターによるこれらの問題の処理の対象です。 C ++には、正規表現と呼ばれるライブラリが付属しています。したがって、正規表現を処理するC ++プログラムは次のように始める必要があります。



#含む

#含む

名前空間stdを使用する;

この記事では、C ++での正規表現の基本について説明します。



記事の内容

正規表現の基礎

正規表現

ここのような文字列は私の男です。上記は、ターゲットシーケンスまたはターゲット文字列、あるいは単にターゲットです。検索されたmanは、正規表現、または単に正規表現です。





マッチング

一致は、検索されている単語またはフレーズが見つかったときに発生すると言われています。マッチング後、交換を行うことができます。たとえば、男性が上に配置された後、女性に置き換えることができます。

シンプルマッチング

次のプログラムは、manという単語がどのように一致するかを示しています。



#含む

#含む

名前空間stdを使用する;

int主要(()。
{{

正規表現reg(('男')。;
もしも ((regex_search((「これが私の男です。」reg)。)。
費用<< 「一致」 <<endl;
そうしないと
費用<< 「一致しません」 <<endl;

戻る 0;
}

関数regex_search()は、一致する場合はtrueを返し、一致しない場合はfalseを返します。ここで、関数は2つの引数を取ります。1つ目はターゲット文字列で、2つ目は正規表現オブジェクトです。正規表現自体は、二重引用符で囲まれた「man」です。 main()関数の最初のステートメントは、正規表現オブジェクトを形成します。正規表現はタイプであり、正規表現は正規表現オブジェクトです。上記のプログラムの出力は、ターゲット文字列に「man」が含まれているため、「matched」です。 'man'がターゲットに表示されなかった場合、regex_search()はfalseを返し、出力は '不一致'になります。

次のコードの出力が一致しません:

正規表現reg(('男')。;
もしも ((regex_search((「これが私の作りです。」reg)。)。
費用<< 「一致」 <<endl;
そうしないと
費用<< 「一致しません」 <<endl;

正規表現「man」がターゲット文字列全体で見つからなかったため、一致しませんでした。「これが私の作成です。」

パターン

上記の正規表現は非常に単純です。正規表現は通常、それほど単純ではありません。正規表現にはメタ文字があります。メタ文字は、特別な意味を持つ文字です。メタ文字は、文字に関する文字です。 C ++正規表現メタ文字は次のとおりです。

^$ 。* + (( )。 [ ] {{ } |

メタ文字の有無にかかわらず、正規表現はパターンです。

キャラクタークラス

角括弧

パターンには、角括弧内に文字を含めることができます。これにより、ターゲット文字列内の特定の位置が角括弧の文字のいずれかに一致します。次のターゲットを検討してください。

「猫は部屋にいます。」

「コウモリは部屋にいます。」

「ネズミは部屋にいます。」

正規表現[cbr] atは、最初のターゲットの猫と一致します。 2番目のターゲットのバットと一致します。 3番目のターゲットのラットと一致します。これは、猫、コウモリ、ラットが「c」、「b」、「r」で始まるためです。次のコードセグメントはこれを示しています。

正規表現reg(('[cbr] at')。;
もしも ((regex_search((「猫は部屋にいます。」reg)。)。
費用<< 「一致」 <<endl;
もしも ((regex_search((「コウモリは部屋にいます。」reg)。)。
費用<< 「一致」 <<endl;
もしも ((regex_search((「ネズミは部屋にいます。」reg)。)。
費用<< 「一致」 <<endl;

出力は次のとおりです。

一致

一致

一致

文字の範囲

パターン[cbr]のクラス[cbr]は、ターゲット内のいくつかの可能な文字と一致します。ターゲットの「c」または「b」または「r」と一致します。ターゲットに「c」、「b」、「r」のいずれも含まれておらず、その後にatが続く場合、一致するものはありません。

「c」、「b」、「r」などの可能性が範囲内に存在します。 0から9までの数字の範囲には10の可能性があり、そのパターンは[0-9]です。小文字のアルファベットの範囲(aからz)には26の可能性があり、そのパターンは[a-z]です。大文字のアルファベットの範囲であるAからZには、26の可能性があり、そのパターンは[A-Z]です。 –は正式にはメタ文字ではありませんが、角括弧内に範囲を示します。したがって、以下は一致を生成します。

もしも ((regex_search((「ID6id」正規表現(('[0-9]')。)。)。

費用<< 「一致」 <<endl;

2番目の引数として正規表現がどのように構成されているかに注意してください。一致は、0から9の範囲の数字6と、ターゲットID6idの6の間で発生します。上記のコードは次のものと同等です。

もしも ((regex_search((「ID6id」正規表現(('[0123456789]')。)。)。

費用<< 「一致」 <<endl;

次のコードは一致を生成します。

charNS[] = 「ID6iE」;

もしも ((regex_search((NS正規表現(('[a-z]')。)。)。

費用<< 「一致」 <<endl;

ここでの最初の引数は文字列変数であり、文字列リテラルではないことに注意してください。一致は、[a-z]の「i」とID6iEの「i」の間です。

範囲はクラスであることを忘れないでください。パターン内の範囲の右側または範囲の左側にテキストを含めることができます。次のコードは一致を生成します。

もしも ((regex_search(('ID2id IDです」正規表現(('ID [0-9] id')。)。)。

費用<< 「一致」 <<endl;

一致はID [0-9] idとID2idの間です。ターゲット文字列の残りの部分はIDであり、この状況では一致しません。

正規表現の主語(regexes)で使用されているように、クラスという単語は実際にはセットを意味します。つまり、セット内の文字の1つが一致することです。

注:ハイフン–は角括弧内のメタ文字であり、範囲を示します。角括弧の外側の正規表現のメタ文字ではありません。

否定

範囲を含むクラスは否定できます。つまり、セット(クラス)内のどの文字も一致しない必要があります。これは、クラスパターンの先頭、開始角括弧の直後に^メタ文字で示されます。したがって、[^ 0-9]は、ターゲット内の適切な位置にある文字と一致することを意味します。これは、0から9までの範囲内の文字ではありません。したがって、次のコードは一致を生成しません。

もしも ((regex_search(('0123456789101112'正規表現(('[^ 0-9]')。)。)。

費用<< 「一致」 <<endl;

そうしないと

費用<< 「一致しません」 <<endl;

0から9の範囲内の数字は、ターゲット文字列の位置0123456789101112のいずれかにあります。したがって、一致はありません–否定。

次のコードは一致を生成します。

もしも ((regex_search((「ABCDEFGHIJ」正規表現(('[^ 0-9]')。)。)。

費用<< 「一致」 <<endl;

ターゲットABCDEFGHIJに数字が見つかりませんでした。一致があります。

[a-z]は[^ a-z]の外側の範囲です。したがって、[^ a-z]は[a-z]の否定です。

[A-Z]は[^ A-Z]の外側の範囲です。したがって、[^ A-Z]は[A-Z]の否定です。

他の否定が存在します。

一致する空白

‘’または tまたは rまたは nまたは fは空白文字です。次のコードでは、正規表現 nはターゲットの「 n」と一致します。

もしも ((regex_search(('1行目。NSNS2行目です。」正規表現(('NS')。)。)。

費用<< 「一致」 <<endl;

任意の空白文字との一致

任意の空白文字に一致するパターンまたはクラスは、[ t r n f]です。次のコードでは、「」が一致しています。

もしも ((regex_search((「ワンツー」正規表現(('[NSNSNSNS] ')。)。)。

費用<< 「一致」 <<endl;

空白以外の文字との一致

空白以外の文字に一致するパターンまたはクラスは、[^ t r n f]です。次のコードは、ターゲットに空白がないため、一致を生成します。

もしも ((regex_search(('1234abcd'正規表現(('[^NSNSNSNS] ')。)。)。

費用<< 「一致」 <<endl;

パターン内のピリオド(。)

パターン内のピリオド(。)は、ターゲット内の nを除くそれ自体を含むすべての文字と一致します。一致は次のコードで生成されます。

もしも ((regex_search(('1234abcd'正規表現(('。')。)。)。

費用<< 「一致」 <<endl;

ターゲットが nであるため、次のコードで一致する結果はありません。

もしも ((regex_search(('NS'正規表現(('。')。)。)。

費用<< 「一致」 <<endl;

そうしないと

費用<< 「一致しません」 <<endl;

注:角括弧付きの文字クラス内では、ピリオドに特別な意味はありません。

マッチングの繰り返し

文字または文字のグループは、ターゲット文字列内で複数回出現する可能性があります。パターンはこの繰り返しに一致する可能性があります。メタ文字、?、*、+、および{}は、ターゲットの繰り返しに一致するために使用されます。 xがターゲット文字列の対象となる文字である場合、メタ文字の意味は次のとおりです。

NS*:一致することを意味します'NS' 0以上回私。何度でも

NS+:一致することを意味します'NS' 1以上回私。少なくとも一度は

NS 一致することを意味します'NS' 0また1 時間

NS{{NS}一致することを意味します'NS'少なくともn回以上。ノートカンマ。

NS{{NS} マッチ'NS'正確にn回

NS{{NSNS}マッチ'NS'少なくともn回ただし、m回以下。

これらのメタ文字は 数量詞。

イラスト

*

*は、前の文字または前のグループと0回以上一致します。 o *は、ターゲット文字列のdogの「o」と一致します。また、本や見た目でooと一致します。正規表現o *は、The animal booooedのbooooと一致します。注:o *はdigと一致し、「o」はゼロ(またはそれ以上)の時間で発生します。

+

+は、前の文字または前のグループと1回以上一致します。 *の場合は0回以上と比較してください。したがって、正規表現e +は、eatの「e」と一致します。「e」は1回発生します。 e +は、「e」が複数回発生する羊のeeとも一致します。注:digでは、「e」が少なくとも1回は発生しないため、e +はdigと一致しません。

NS ?前の文字または前のグループに0回または1回(それ以上ではない)一致します。だから、e? 「e」はdig、ゼロ時間で発生するため、digと一致します。 e? 「e」がセット内で1回発生するため、セットに一致します。注:e?まだ羊と一致します。羊には2つの「e」がありますが。ここには微妙な違いがあります–後で参照してください。

{NS、}

これは、先行する文字または先行するグループの少なくともn回の連続した繰り返しに一致します。したがって、正規表現e {2、}は、ターゲットの羊の2つの「e」と、ターゲットの羊の3つの「e」に一致します。セットには「e」が1つしかないため、e {2、}はセットと一致しません。

{NS}

これは、先行する文字または先行するグループのn回の連続した繰り返しに正確に一致します。したがって、正規表現e {2}は、ターゲットである羊の2つの「e」と一致します。セットには「e」が1つしかないため、e {2}はセットと一致しません。ええと、e {2}はターゲットの2つの「e」と一致します。ここには微妙な違いがあります–後で参照してください。

{n、m}

これは、nからmまでの任意の場所で、先行する文字または先行するグループの複数の連続した繰り返しに一致します。したがって、e {1,3}は、「e」がないdigでは何にも一致しません。セット内の1つの「e」、羊の2つの「e」、羊の3つの「e」、羊の3つの「e」と一致します。最後の試合にはニュアンスがあります-後で見てください。

マッチングオルタネーション

コンピューター内の次のターゲット文字列について考えてみます。

農場にはさまざまなサイズの豚がいます。

プログラマーは、このターゲットがヤギ、ウサギ、ブタのいずれであるかを知りたい場合があります。コードは次のようになります。

charNS[] = 「農場にはさまざまなサイズの豚がいます。」;

もしも ((regex_search((NS正規表現((「ヤギ|卯|豚」)。)。)。

費用<< 「一致」 <<endl;

そうしないと

費用<< 「一致しません」 <<endl;

コードは一致を生成します。交互文字|の使用に注意してください。 2つ、3つ、4つ、およびそれ以上のオプションがあります。 C ++は、最初に、ターゲット文字列の各文字位置で、最初の選択肢であるヤギを一致させようとします。ヤギで成功しない場合は、次の選択肢であるウサギを試します。ウサギで成功しない場合は、次の選択肢であるブタを試します。 pigが失敗した場合、C ++はターゲットの次の位置に移動し、最初の選択肢から再開します。

上記のコードでは、pigが一致しています。

マッチングの開始または終了

始まり


^が正規表現の先頭にある場合、ターゲット文字列の先頭テキストを正規表現と一致させることができます。次のコードでは、ターゲットの開始はabcであり、これは一致しています。

もしも ((regex_search(('abc and def'正規表現(('^ abc')。)。)。

費用<< 「一致」 <<endl;

次のコードでは一致は発生しません。

もしも ((regex_search((「はい、abcとdef」正規表現(('^ abc')。)。)。

費用<< 「一致」 <<endl;

そうしないと

費用<< 「一致しません」 <<endl;

ここでは、abcはターゲットの先頭にありません。

注:曲折アクセント記号「^」は、正規表現の先頭にあるメタ文字であり、ターゲット文字列の先頭に一致します。これは、文字クラスの開始時にまだメタ文字であり、クラスを否定します。

終わり

$が正規表現の末尾にある場合、ターゲット文字列の終了テキストを正規表現と一致させることができます。次のコードでは、ターゲットの終わりはxyzであり、これは一致しています。

もしも ((regex_search((「uvwとxyz」正規表現(('xyz $')。)。)。

費用<< 「一致」 <<endl;

次のコードでは一致は発生しません。

もしも ((regex_search(('uvw and xyz final'正規表現(('xyz $')。)。)。

費用<< 「一致」 <<endl;

そうしないと

費用<< 「一致しません」 <<endl;

ここで、xyzはターゲットの終わりではありません。

グループ化

括弧を使用して、パターン内の文字をグループ化できます。次の正規表現を検討してください。

「コンサート(ピアニスト)」

ここのグループは、メタ文字(と)に囲まれたピアニストです。それは実際にはサブグループですが、コンサート(ピアニスト)はグループ全体です。次のことを考慮してください。

「(ピアニストはいい)」

ここで、サブグループまたはサブストリングは、ピアニストが良いです。

共通部分のあるサブストリング

簿記係は本の世話をする人です。簿記係と本棚のある図書館を想像してみてください。次のターゲット文字列のいずれかがコンピュータにあると想定します。

'図書館には賞賛される本棚があります。';

'これが簿記係です。';

'本棚は本棚と連携します。';

プログラマーの関心は、これらの文のどれがコンピューターにあるかを知ることではないと仮定します。それでも、彼の興味は、コンピューター内のターゲット文字列に本棚または簿記係が存在するかどうかを知ることです。この場合、彼の正規表現は次のようになります。

「本棚|簿記係。」

交互を使用します。

両方の単語に共通する本が、パターン内の2つの単語に2回入力されていることに注意してください。本を2回入力するのを避けるために、正規表現は次のように書く方がよいでしょう。

「本(棚|キーパー)」

ここでは、グループ、shelf | keeper交互のメタ文字がまだ使用されていますが、2つの長い単語には使用されていません。これは、2つの長い単語の2つの末尾部分に使用されています。 C ++は、グループをエンティティとして扱います。したがって、C ++は、本の直後に来る棚またはキーパーを探します。次のコードの出力が一致します。

charNS[] = 「図書館には賞賛される本棚があります。」;

もしも ((regex_search((NS正規表現((「本(棚|キーパー)」)。)。)。

費用<< 「一致」 <<endl;

簿記係ではなく本棚が一致しました。

icaseおよび複数行のregex_constants

icase

デフォルトでは、マッチングでは大文字と小文字が区別されます。ただし、大文字と小文字を区別しないようにすることができます。これを実現するには、次のコードのように、regex :: icase定数を使用します。

もしも ((regex_search(('フィードバック'正規表現(('餌'正規表現:::icase)。)。)。

費用<< 「一致」 <<endl;

出力が一致します。したがって、大文字の「F」を使用したフィードバックは、小文字の「f」を使用したフィードと一致しています。 regex :: icaseは、regex()コンストラクターの2番目の引数になりました。それがなければ、ステートメントは一致を生成しません。

マルチライン

次のコードについて考えてみます。

charNS[] = 'ライン1NS2行目NS3行目;

もしも ((regex_search((NS正規表現(('^。* $')。)。)。

費用<< 「一致」 <<endl;

そうしないと

費用<< 「一致しません」 <<endl;

出力が一致していません。正規表現^。* $は、ターゲット文字列の最初から最後まで一致します。 。*は、 nを除く、0回以上の任意の文字を意味します。したがって、ターゲットに改行文字( n)があるため、一致するものはありませんでした。

ターゲットは複数行の文字列です。 「。」が改行文字と一致するためには、定数regex :: multilineを作成する必要があります。これは、regex()構文の2番目の引数です。次のコードはこれを示しています。

charNS[] = 'ライン1NS2行目NS3行目;

もしも ((regex_search((NS正規表現(('^。* $'正規表現:::マルチライン)。)。)。

費用<< 「一致」 <<endl;

そうしないと

費用<< 「一致しません」 <<endl;

ターゲット文字列全体のマッチング

改行文字( n)を含まないターゲット文字列全体を照合するには、regex_match()関数を使用できます。この関数はregex_search()とは異なります。次のコードはこれを示しています。

charNS[] = '第一、第二第三';

もしも ((regex_match((NS正規表現(('。*2番目。*')。)。)。

費用<< 「一致」 <<endl;

ここに一致があります。ただし、正規表現はターゲット文字列全体と一致し、ターゲット文字列には「 n」が含まれていないことに注意してください。

match_resultsオブジェクト

regex_search()関数は、ターゲットと正規表現オブジェクトの間の引数を取ることができます。この引数はmatch_resultsオブジェクトです。一致した(一部の)文字列全体と一致したサブ文字列を知ることができます。このオブジェクトは、メソッドを持つ特別な配列です。 match_resultsオブジェクトタイプはcmatch(文字列リテラルの場合)です。

一致の取得

次のコードについて考えてみます。

charNS[] = 「あなたが探していた女性!」;

cmatch m;

もしも ((regex_search((NSNS正規表現((「w.m.n」)。)。)。

費用<<NS[0] <<endl;

ターゲット文字列には、womanという単語が含まれています。出力は女性です。これは正規表現w.m.nに対応します。インデックス0では、特別な配列が唯一の一致である女性を保持します。

クラスオプションを使用すると、ターゲットで最初に見つかったサブ文字列のみが特別な配列に送信されます。次のコードはこれを示しています。

cmatch m;

もしも ((regex_search((「ネズミ、ネコ、コウモリ!」NS正規表現(('[bcr] at')。)。)。

費用<<NS[0] <<endl;

費用<<NS[1] <<endl;

費用<<NS[2] <<endl;

出力はインデックスゼロからのラットです。 m [1]とm [2]は空です。

別の方法では、ターゲットで最初に見つかったサブ文字列のみが特別な配列に送信されます。次のコードはこれを示しています。

もしも ((regex_search((「うさぎ、山羊、豚!」NS正規表現((「ヤギ|卯|豚」)。)。)。

費用<<NS[0] <<endl;

費用<<NS[1] <<endl;

費用<<NS[2] <<endl;

出力はインデックスゼロからのウサギです。 m [1]とm [2]は空です。

グループ化

グループが関係している場合、一致した完全なパターンは、特別な配列のセル0に入ります。次に見つかったサブ文字列はセル1に入ります。次のサブ文字列はセル2に入ります。等々。次のコードはこれを示しています。

もしも ((regex_search((「今日の最高の本屋!」NS正規表現(('本((sel)(ler))')。)。)。

費用<<NS[0] <<endl;

費用<<NS[1] <<endl;

費用<<NS[2] <<endl;

費用<<NS[3] <<endl;

出力は次のとおりです。

書店

売り手

細胞

読んだ

グループ(売り手)はグループ(売り手)の前に来ることに注意してください。

試合の位置

cmatch配列内の各サブ文字列の一致位置を知ることができます。カウントは、ターゲット文字列の最初の文字の位置0から始まります。次のコードはこれを示しています。

cmatch m;

もしも ((regex_search((「今日の最高の本屋!」NS正規表現(('本((sel)(ler))')。)。)。

費用<<NS[0] << '->' <<NS。ポジション((0)。 <<endl;

費用<<NS[1] << '->' <<NS。ポジション((1)。 <<endl;

費用<<NS[2] << '->' <<NS。ポジション((2)。 <<endl;

費用<<NS[3] << '->' <<NS。ポジション((3)。 <<endl;

引数として、セルインデックスとともにpositionプロパティを使用していることに注意してください。出力は次のとおりです。

書店->5

売り手->9

細胞->9

読んだ->12

検索と置換

新しい単語またはフレーズで一致を置き換えることができます。これには、regex_replace()関数が使用されます。ただし、今回は、置換が発生する文字列は文字列リテラルではなく、文字列オブジェクトです。したがって、文字列ライブラリをプログラムに含める必要があります。図:

#含む

#含む

#含む

名前空間stdを使用する;

int主要(()。
{{
文字列str= 「ここに、私の男が来ます。あなたの男が行きます。」;
文字列newStr=regex_replace((NS正規表現(('男')。 '女性')。;
費用<<newStr<<endl;

戻る 0;
}

ここでコーディングされているregex_replace()関数は、すべての一致を置き換えます。関数の最初の引数はターゲット、2番目は正規表現オブジェクト、3番目は置換文字列です。この関数は、ターゲットであるが置換されている新しい文字列を返します。出力は次のとおりです。

これが私の女性です。あなたの女性が行きます。

結論

正規表現は、パターンを使用して、ターゲットシーケンス文字列のサブ文字列を照合します。パターンにはメタ文字があります。 C ++正規表現で一般的に使用される関数は、regex_search()、regex_match()、およびregex_replace()です。正規表現は、二重引用符で囲まれたパターンです。ただし、これらの関数は、正規表現だけでなく、正規表現オブジェクトを引数として取ります。これらの関数で使用する前に、正規表現を正規表現オブジェクトにする必要があります。