正規表現:「行頭」「行末」の表現と、応用例

最終更新:2018-07-20 by Joe

正規表現の基本、行頭(行の先頭)と行末(行の末尾)を表す表現です。

行頭(行の先頭)を表す正規表現

正規表現において、行頭(行の先頭)は「^」によって、その位置をマッチできます。「^」はキャレット、または、ハットと読みます。

「^(ハット、キャレット)」を使った正規表現の例

例えば下記は、行頭が「ラーメン」で始まる文字列全体をマッチします。

// 行頭が「ラーメン」で始まる文字列にマッチする正規表現
/^ラーメン.*/

// マッチする文字列
ラーメン大好き小池さん。

「^」は何らかの文字をマッチするのではなく「位置」をマッチする点に注意して下さい。正規表現では、このような位置を表す表現は、「位置指定子」や「アンカー」などと呼ばれます。

上記の例では、「.(ドット)」は「改行以外の1文字」を表し、また「*」は、直前のパターンの0回以上の連続(上記の例では「.」の連続)を表します。このような正規表現のメタ文字の一覧はこちらの記事に詳しくまとめました。

「^」という記号によって、文頭の「位置」を表せるんだね。

行頭の最初の1文だけをマッチさせる

「/^ラーメン.*。/」の正規表現を使って、下記について考えてみます。

「ラーメン大好き小池さん。昔ながらの愉快なキャラクターが人気です。」

先程の例は、文章の全体(ラーメン・・・人気です。)をマッチします。

// 行頭に「ラーメン」、「。」で終わる文字列にマッチする正規表現
/^ラーメン.*。/

// 対象文字列
ラーメン大好き小池さん。昔ながらの愉快なキャラクターが人気です。

// マッチする文字列
ラーメン大好き小池さん。昔ながらの愉快なキャラクターが人気です。

これは、正規表現がデフォルトで「最長一致(Greedy matching)」を探す特徴があるので、「.*」がマッチする文字列の中で、最も長いパターンを優先的にマッチするです。

でも、もし「ラーメン大好き小池さん。」という行頭から最初の1分だけをのマッチングを得たい時、「最短一致」を探す必要があります。

「最短一致(Non-greedy matching)」を探すには、量指定子「*」に「?」を組み合わせます。

// 行頭に「ラーメン」、「。」で終わる文字列で、最小のものにマッチする正規表現
/^ラーメン.*?。/

// 対象文字列
ラーメン大好き小池さん。昔ながらの愉快なキャラクターが人気です。

// マッチする文字列
ラーメン大好き小池さん。

最長・最短一致に関しては、こちらの記事もぜひご覧ください

行末(行の末尾)を表す正規表現

行末(行の末尾)を表す位置指定子は「$」です。

「$」を使った正規表現の例

「大好きなのは、唐揚げ弁当。あと、のり弁も安いから好き。」で終了する文字列を探してみます。

// 行末に「。」マッチする正規表現
/.*。$/

// 処理対象文字列
大好きなのは、唐揚げ弁当。あと、のり弁も安いから好き。

// マッチする文字列
大好きなのは、唐揚げ弁当。あと、のり弁も安いから好き。

マッチングはうまくいきましたが、ただ、さきほどの例と同様、2つの文章を含むすべての文字列をマッチしてしまいます。

行末の最後の一文だけをマッチさせる

たとえば、すべての文字列でなく「あと、のり弁も安いから好き。」という行の末尾の後半の一文だけをマッチするように書き換えます。

試しに、これでどうでしょうか?

// 行末の最後の一文をマッチ?
/.*?。$/

// 処理対象文字列
大好きなのは、唐揚げ弁当。あと、のり弁も安いから好き。

// マッチする文字列
大好きなのは、唐揚げ弁当。あと、のり弁も安いから好き

これはうまく行きませんでした。

正規表現は左側から処理して行きますので、戻り方向(左方向)への最短を吟味しません。先に「.*?」が最初の文章全体をマッチしてしまいます

このようなケースには工夫が必要です。

いくつか方法が考えられますが、下記は「否定の文字クラス」を利用した例です。「[^。]*」により、「。以外の一文字の連続」をマッチします。これにり、「。」で終わる行末の文字列でで、かつ、「。」を含まない連続がマッチできます。

// 「。」を含まない文章で、行末にある最後の1文「。」で終わる文章の正規表現
//[^。]*。$/u$/

// 処理対象文字列
大好きなのは、唐揚げ弁当。あと、のり弁も安いから好き。

// マッチする文字列
あと、のり弁も安いから好き。

うまくいきました。

下記の記事で、正規表現の「否定先読み」表現についてまとめています。

行末、行頭は、「^」「$」を使ってマッチすることが分かったけど、うまく応用する事が大事なんだね。

【補足】位置指定子(アンカー)について

文頭、文末をあらわす「^」「$」は、いずれも「位置」を限定し、それ自体は文字をマッチングしません。それゆえ、これらは「位置指定子」や「アンカー」と呼ばれています。

より複雑な位置指定子には、他に、下記のような物があります。

  • 肯定先読み  : (?= 文字列)
  • 肯定戻り読み : (?<= 文字列)
  • 否定先読み  : (?! 文字列)
  • 否定戻り読み : (?<! 文字列)

厳密には「位置指定子」ではないのですが、特定の位置をマッチングするために利用できます。

これらを初めて知った方は「なんなくこんな方法があるんだなあ」というくらいに覚えておくと良いと思います。きっと近い将来、役に立つでしょう。

いちおう、利用例をあげておきます。

「のり弁」を含む一文をマッチさせる

少しトリッキーですね。「一文」を「『。』の直後から、次の『。』まで」という前提にして「のり弁」を含む一文をマッチします。この文章が行頭にあるのか、行末にあるのかは、ケアしないので、「^」、「$」は利用できません。

// のり弁当を含み、「。=で終わる1文。
/[^。]*(?=のり弁)[^。]*。*/

// 処理対象
大好きなのは、唐揚げ弁当。あと、のり弁当も安いから好き。好き好き〜。


// マッチング
あと、のり弁当も安いから好き。

参考リンク

正規表現に関連する記事です。