正規表現

以下は、ruby がサポートする正規表現記号(メタ文字)の一覧です。

という規則があります。

以下の説明の中で「多バイト文字に対応した正規表現」とは、 $KCODE が設定されているか、あるいは明示的に漢字オプショ ン(正規表現リテラルを参照)を指定するなどで多バイト文字 にマッチする正規表現を指します。

後方参照

正規表現 \1 \2 ... \n は、後方参照です。n 番目の括弧(正規 表現 ( ) グルーピング)にマッチした文字列にマッチします。

/((foo)bar)\1\2/

は、

/((foo)bar)foobarfoo/

と同じです。

例:

re = /(foo|bar|baz)\1/
p re =~ 'foofoo'   # => 0
p re =~ 'barbar'   # => 0
p re =~ 'bazbaz'   # => 0
p re =~ 'foobar'   # => nil

対応する括弧は、後方参照よりも左側にないといけません。

対応する括弧の中に後方参照があれば常にマッチに失敗します。 また、対応する括弧がない 1 桁の後方参照も常にマッチに失敗します。

p /(\1)/ =~ "foofoofoo" # => nil
p /(foo)\2/ =~ "foo\2"  # => nil

2 桁以上の後方参照も指定できますが、バックスラッシュ記法\nnn (8進 nnn に対応する文字)と混同しないように注意する必要が あります。数値が 1 桁なら常に後方参照です。2 桁以上の指定では、対応す る括弧がなければ 8 進コードと見なされます。

また、逆に正規表現中に 8 進で 1 桁のコードを記述するには \01 など 0 で 始める必要があります(\0 という後方参照はないので曖昧になりません)。

p   /\1/ =~ "\1"   # => nil     # 対応する括弧のない後方参照
p  /\01/ =~ "\1"   # => 0       8 進コード
p  /\11/ =~ "\11"  # => 0       8 進コード

# 8 進コード (対応する括弧がないので)
p /(.)\10/ =~ "1\10" # => 0

# 後方参照 (対応する括弧があるので)
p /((((((((((.))))))))))\10/ =~ "aa"  # => 0

# 8 進コード(ただし、"\0" + "8" になっている
# \08 という 8 進コードはないので)
p /(.)\08/ =~ "1\0008" # => 0

# 後方参照に続けて数字を書きたいなら括弧でグループ化して区切る
# などするしかない。
p /(.)(\1)1/ =~ "111"   # => 0

文字クラス

正規表現 [ ] は、文字クラス指定です。[] 内に列挙したいずれかの一 文字にマッチします。

例えば、/[abc]/ は、"a", "b", "c" いずれか一文字にマッチします。 ASCIIコード順で連続する文字列は間に `-' を置いて /[a-c]/ のように書 くこともできます。また、先頭が `^' であれば指定した文字以外の一文字 とマッチします。

先頭以外にある `^' はその文字そのものとマッチします。また、先頭、末 尾にある `-' は、その文字そのものとマッチします。

p /[a^]/ =~ "^"   # => 0
p /[-a]/ =~ "-"   # => 0
p /[a-]/ =~ "-"   # => 0
p /[-]/ =~ "-"   # => 0

空の文字クラスはエラーになります。

p /[]/ =~ ""
p /[^]/ =~ "^"
# => invalid regular expression; empty character class: /[^]/

先頭(あるいは否定の "^" の直後)にある "]" は、文字クラスの終りではなく "]" そのものを表します。

p /[]]/ =~ "]"       # => 0
p /[^]]/ =~ "]"      # => nil

"^", "-", "]" そして "\\"(バックスラッシュ)は、バックスラッシュでエス ケープして、その文字にマッチさせることができます。

p /[\^]/ =~ "^"   # => 0
p /[\-]/ =~ "-"   # => 0
p /[\]]/ =~ "]"   # => 0
p /[\\]/ =~ "\\"  # => 0

[] 内には文字列と同じバックスラッシュ記法と、 正規表現 \w, \W, \s, \S, \d, \D (これらは文字クラスの略記法です)が 使用できます。 *2

否定による以下のような文字クラスは改行文字にもマッチすることに 注意してください(正規表現 \W,\D も同様)。

p /[^a-z]/ =~ "\n"    # => 0

文字クラスの中では以下の特殊な指定が使用できますが、この機能は将来に渡っ てサポートされるとは約束されていません(なのでここでは詳細は書きません 詳細を知りたい方は grep(1) 等のマニュアルを参照して ください)。

[:alnum:]  数字とアルファベット 0-9a-zA-Z
[:alpha:]  アルファベット a-zA-Z
[:blank:]  空白類
[:cntrl:]  コントロール文字
[:digit:]  数字
[:graph:]  空白を除く印字可能な可視文字
[:lower:]  小文字
[:print:]  可視文字
[:punct:]  記号
[:space:]  空白文字
[:upper:]  大文字
[:xdigit:] 16進文字

例: ("[]" を含めて "[:...:]" が1文字を表していることに注意。 文字クラスの "[]" ではない)

p /[[:alnum:][:cntrl:]]/ =~ "a\x01"  # => 0

注: 全角文字は考慮されません。正規表現が漢字にマッチするように指定さ れていても [:alpha:] などは、全角のアルファベットとはマッチしません。

p /[[:alpha:]]/e =~ "A"        # => nil

バックトラック

*3

(?> ) という特殊な括弧で正規表現をかこむと、その括弧の中の表現に マッチした部分ではバックトラックが起こりません。その意味を例を挙げて 見てみます。

例えば通常の正規表現では

p /(a*)ab/ === 'aaab'

はマッチします。その過程は以下のようになります。

  1. 正規表現 a* がインデックス 0 で a みっつにマッチする
  2. 正規表現 a がマッチに失敗
  3. 正規表現 a* がマッチした分を少し「あきらめさせて」、 a ふたつにマッチさせる (バックトラックする)
  4. 正規表現 aa にマッチする
  5. 正規表現 bb にマッチする

しかしこの正規表現の括弧を (?> ) に変えるとマッチしなくなります。 その過程は以下のようになります。

  1. 正規表現 a* がインデックス 0 で a みっつにマッチする
  2. 正規表現 a がマッチに失敗
  3. a* がマッチした分をすこし減らして試したいが、 抑止指定されているのですぐに失敗する
  4. 正規表現 a* がインデックス 1 で a ふたつにマッチする

以下同じように失敗して、最終的にマッチ全体が失敗します。

ひらたく言うと、通常の正規表現の基本が「欲張りマッチ」なのに対して、 (?> ) は一回取ったものは絶対に離さない「超欲張りマッチ」を行います。


*1より良い例があれば、書き換えてください。役に立つ。わかりやすい が原則
*2 文字クラスの中では . や * はバックスラッシュでエスケープする 必要はありません。(しても構いません。)
*3ruby-list:28084[外部] 以下のスレッドも参照してください。