Ruby 正規表現 スクリプトの書き方

バイオインフォ道場、くまぞうです。

正規表現とは

正規表現は、文字列をパターンで表現する方法です。テキストエディタの検索に用いられたり、プログラムでテキストを用いた条件判断に使われたりします。ほとんどのプログラム言語で正規表現を使うことが出来るほか、sedやAwk・grepなどの有名なツールでも正規表現を使って、フィルタリングや置換処理を行います。

スポンサーリンク



基本正規表現

正規表現は色々なプログラム言語やツールで使われるので、基本的な表現方法は共通しています。色々な場面で活用出来るので、最低限で覚える場合はこの表現から覚えると良いと思います。

  • .
    任意の一文字にマッチ

  • [abc]
    カッコ内の何れかの文字にマッチ。-を使うと範囲を表す。a-zは小文字のa,b,c….z。

  • [^abc]
    カッコ内の文字の否定。行の先頭を表す^と区別して使う。

  • ^
    行の先頭を表す。他の文字と組合せて判断することが多い。^#の場合、先頭に「#」。

  • $
    行の最後を表す。他の文字と組合せて判断することが多い。\.$の場合、ピリオド終了行。

  • (…)
    括弧()で囲むと、判断後、呼び出すことができる。一致順に、$1,$2…$9で呼出が可能。

  • *
    0回以上の繰り返し。/[0-9]*[0-9]/は数字の連続を表す。

  • {m,n}
    m回以上のn回以下の繰り返し。{m}は指定回数の繰り返し、{m,}は指定回数以上の繰り返し。

regexp1.rb

#! /usr/bin/ruby

puts "TARGET STRINGS"
puts "> " + (aaa = "hello")
puts "> " + (bbb = "world!")
puts "> " + (ccc = "Hello world!")
puts 

ptns = [' ',             # 空白を含む
        "[Hw]",          # H or hを含む
        "^h",            # 先頭がh
        "[^a-zA-Z]$",    # 末尾がalphabet以外
        "l{2,}",         # lが2個以上繰り返し
        " ([a-z]*[a-z])" # 空白後のalphabetの連続部位を保持
       ]

ptns.each do |ptn|
  re = Regexp.new(ptn)
  puts re.inspect  # 正規表現パターンの表示

  # TARGET STRINGに対して、正規表現パターンをチェック
  [aaa, bbb, ccc].each do |x|
    pos = (x =~ re)
    pos = !pos ? "not match" : sprintf("%2s", pos.to_s) + "(match)"
    printf "%-12s : %s%s\n", x, pos, (ptn.include?('(') && $~) ? " -> $1=#{$1}" : ""
  end
  puts
end
$ ruby regexp1.rb
TARGET STRINGS
> hello
> world!
> Hello world!

/ /
hello        : not match
world!       : not match
Hello world! :  5(match)

/[Hw]/
hello        : not match
world!       :  0(match)
Hello world! :  0(match)

/^h/
hello        :  0(match)
world!       : not match
Hello world! : not match

/[^a-zA-Z]$/
hello        : not match
world!       :  5(match)
Hello world! : 11(match)

/l{2,}/
hello        :  2(match)
world!       : not match
Hello world! :  2(match)

/ ([a-z]*[a-z])/
hello        : not match
world!       : not match
Hello world! :  5(match) -> $1=world

その他の正規表現

基本的な表現以外にも色々な正規表現があります。但し、特定のプログラミング言語やツールだけで有効なものもあるので注意が必要です。尚、使いこなせるようになるとマッチングにとても役に立つと思います。

  • \d
    数字にマッチ

  • \D
    数字以外にマッチ

  • \s
    空白文字にマッチ

  • \S
    空白文字にマッチ

  • \w
    単語に使える文字にマッチ

  • \W
    単語に使える文字以外にマッチ

  • ?
    控えめな繰り返し。/re?/

  • abc|xyz
    abcまたはxyz

  • d(o|i)g
    dogまたはdig

regexp2.rb

#! /usr/bin/ruby

puts "TARGET STRINGS"
puts "> " + (aaa = "abcd 1234 +-/")
puts 

ptns = ['\d',      # 数字
        '\D',      # 数字以外
        '\s',      # 空白
        '\S',      # 空白以外
        '\w',      # 単語に使える文字
        '\W',      # 単語に使える文字以外
        'a.* ',    # 貪欲なmatch
        'a.*? ',   # 控え目なmatch
        'abc|xyz', # abc または xyz
        '1(2|0)3'  # 123 または 103
       ]

ptns.each do |ptn|
  re = Regexp.new(ptn)
  puts re.inspect  # 正規表現パターンの表示

  # TARGET STRINGに対して、正規表現パターンをチェック
  [aaa].each do |x|
    pos = (x =~ re)
    pos = !pos ? "not match" : sprintf("%2s", pos.to_s) + "(match)"
    printf "%-12s : %s%s\n", x, pos, (ptn.include?('*') && $~) ? " -> #{$&}" : ""
  end
  puts
end
$ ruby regexp2.rb
TARGET STRINGS
> abcd 1234 +-/

/\d/
abcd 1234 +-/ :  5(match)

/\D/
abcd 1234 +-/ :  0(match)

/\s/
abcd 1234 +-/ :  4(match)

/\S/
abcd 1234 +-/ :  0(match)

/\w/
abcd 1234 +-/ :  0(match)

/\W/
abcd 1234 +-/ :  4(match)

/a.* /
abcd 1234 +-/ :  0(match) -> abcd 1234 

/a.*? /
abcd 1234 +-/ :  0(match) -> abcd 

/abc|xyz/
abcd 1234 +-/ :  0(match)

/1(2|0)3/
abcd 1234 +-/ :  5(match)

正規表現によるパターンマッチ結果へのアクセス

Rubyによる正規表現のパターンマッチの結果は、色々な情報から構成されています。マッチした部分だけでなく、その前後など、便利な方法が提供されています。マッチ情報のアクセス方法は、$~を中心としたグローバル変数を使用した方法と、Regexp.last_matchを中心とした配列様のアクセス方法があります。

regexp3.rb

#! /usr/bin/ruby

require 'pp'

puts "TARGET STRINGS : #{(aaa = "abcd 1234")}"
puts

# 正規表現パターンマッチ1
re = Regexp.new('(\w) (\d)')
puts re.inspect
aaa =~ re
# マッチ情報にグローバル変数を使ってアクセス
puts "match      : #{$&}"
puts "pre match  : #{$`}"
puts "post match : #{$'}"
puts "$1         : #{$1}"
puts "$2         : #{$2}"
puts

# 正規表現パターンマッチ2
match_info = Regexp.last_match
# マッチ情報にグローバル変数を使ってアクセス
puts "match      : #{match_info[0]}"
puts "pre match  : #{match_info.pre_match}"
puts "post match : #{match_info.post_match}"
puts "$1         : #{match_info[1]}"
puts "$2         : #{match_info[2]}"
$ ruby regexp3.rb
TARGET STRINGS : abcd 1234

/(\w) (\d)/
match      : d 1
pre match  : abc
post match : 234
$1         : d
$2         : 1

match      : d 1
pre match  : abc
post match : 234
$1         : d
$2         : 1
スポンサーリンク