箱のプログラミング日記。

えんじにあ奮闘記

Rubyで正規表現を使いたい

f:id:y_hakoiri:20191102121618j:plain

久しぶりにRuby記事。

前々から苦手意識が拭えなかった正規表現を理解できたのでまとめておく。

正規表現オブジェクト

そもそも正規表現自体がオブジェクト。

きちんと考えれば分かることだけど、今までちゃんと意識したことなかった。

正規表現オブジェクトの作成方法はいくつかあって

reg = /abc/
=> /abc/
reg.class
=> Regexp

//でパターンを囲む方法。

これが最も一般的かな。よく使う。

その他、Regexpクラスからnewすることもできる。

reg = Regexp.new("hoge")
=> /hoge/
reg.class
=> Regexp

%rにより作成することもできる。

reg = %r!fuga!
=> /fuga/
reg.class
=> Regexp

これもたまに見る。

ググって出てくる記事によって採用してる作り方が違って、きちんとした違いを知らずに%r/を混同して(一緒に)使ってみたことがあったりした。そりゃいつまで経っても理解できないですね。笑

余談 ~2020/04/26追記~

リテラル(//で囲んで生成)とnewでオブジェクトを作成する方法には以下のような違いがあるらしい。

正規表現リテラルはコードを書いた時点で決まったパターンの正規表現オブジェクトを作成する構文です。 一方で、RegExpコンストラクタは変数と組み合わせるなど、実行時に変わることがあるパターンの正規表現オブジェクトを作成できます。

参考:文字列 · JavaScript Primer #jsprimer

(JSの教材だけど...)

普段開発していて、えー今ここ関係ないのにエラーになるんだぁって思うことがたまにあったけど

呼び出してなくても読み込みのタイミングが早い場合は、関係ない箇所でもエラーになるということだね

正規表現リテラルは、ロード時に正規表現のパターンが評価されるため、\sの連続する回数を動的に変更することはできません。 一方で、RegExpコンストラクタは、実行時に正規表現のパターンが評価されるため、変数を含んだ正規表現オブジェクトを作成できます

動的な値を正規表現のマッチパターンとして使いたい場合は、リテラルではなくnewでオブジェクトを作成する必要がありそう。

実例を見てみる

ググるといろんなパターン一覧が出てくるけど、具体的にRailsのアプリケーション内とかでどう使うのかが分からないことが多々あったので。

例えばバリデーションだと

validates :tel, format: { with: /\A\d{10}\z|\A\d{11}\z/ }

//の部分が正規表現オブジェクト。

/\A\d{10}\z|\A\d{11}\z/

いろんな記号やら数値やらがあって混乱してしまう前に、冷静に一つずつ分解していこう

パターン部分は//の中身なので、

\A\d{10}\z|\A\d{11}\z

ここだけ見れば良い。さらに|は「もしくは」を表現するので、

\A\d{10}\z
# もしくは
\A\d{11}\z

となる。

さらにエスケープ\で分解して見てみると

\A
\d{10}
\z

こうなる。

\はエスケープで、直後の文字が文字列でない(記号である)ことを表す。ここまで来てやっと「エスケープがあるということは記号なので、正規表現一覧を見にいこう」という段階まで到達。

  • \A...ファイルの先頭にマッチ
  • \z...ファイルの末尾にマッチ
  • \d...すべての数字
  • {n}...直前のパターンをn回繰り返し

ということで、\A\d{10}\zは10桁の数字、\A\d{11}\zは11桁の数字を表し、/\A\d{10}\z|\A\d{11}\z/は「10桁もしくは11桁の数字」というパターンになる。

数値は\d以外にも[0-9]と表現することもできる。

参考

基本的な正規表現一覧 | murashun.jp

【Regexp】正規表現まとめ(基礎)[Ruby編] - Qiita