7
0

More than 1 year has passed since last update.

空白か先頭か(あるいは空白か文末)という正規表現

Last updated at Posted at 2022-04-26

正規表現で少し詰まったので、記事としてアウトプットしておく。

Ruby 2.7.6で検証しています。

やりたいこと

(空白か先頭)特定の文字列(空白か文末)という正規表現を書きたい。改行は入らないので考慮を今回はせず1行の文字列で考えます。
この正規表現を特定の文字列strに対して、reg(str)としましょう。

具体的には

> ' 大阪市'.match?(`reg('大阪市')`)
=> true

> ' 大阪市'.match?(`reg('大阪')`)
=> false

> ' 大阪 市'.match?(`reg('大阪')`)
=> true

のようなイメージ。純粋にinclude?関数を使うと、後者はtrueになってしまうので別途正規表現を作る必要が出てきました。

こんな正規表現を書いた

> ' 大阪市'.match?(/[\s|\A]#{'大阪市'}[\s|\z]/)
=> false
> ' 大阪市'.match?(/[\s|\A]#{'大阪'}[\s|\z]/)
=> false

通常の文字(aとかとか)であれば[]を使えばいいのですが、[]は文字クラスであり、\Aはアンカー(文字ではない。位置にマッチする表現)ので動きません。

グループを使おう

今回やりたい正規表現は下記の通りでした。

> ' 大阪市'.match?(/(\A|\s)#{'大阪市'}(\s|\z)/)
=> true
> ' 大阪市'.match?(/(\A|\s)#{'大阪'}(\s|\z)/)
=> false

空白と先頭のグループにマッチするかを判定、直後に特定の文字列があるかを確認して、更にその直後に空白と文末のグループにマッチするかを見る、という表現になりました。

もう一歩踏み込んで

グループに?:をつけることで、キャプチャせずにグループ化を行うことができ、若干早くなるみたいです。

> ' 大阪市'.match?(/(?:\A|\s)#{'大阪市'}(?:\s|\z)/)
=> true
> ' 大阪市'.match?(/(?:\A|\s)#{'大阪'}(?:\s|\z)/)
=> false

更に、上記だと全角スペースや非ASCIIの空白文字の対応が漏れてしまっているので、\s[[:space:]]にして

> ' 大阪市'.match?(/(?:\A|[[:space:]])#{'大阪市'}(?:[[:space:]]|\z)/)
=> true
> ' 大阪市'.match?(/(?:\A|[[:space:]])#{'大阪'}(?:[[:space:]]|\z)/)
=> false

とするのが良さそうです(@scivolaさんありがとうございました!)。

REF

正規表現 (Ruby 3.1 リファレンスマニュアル)

7
0
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
0