Perl の正規表現

Posted on Tue 07 January 2014 in blog

マッチ演算子

評価の結果は真偽値としては、マッチすれば真、そうでなければ偽。 and, or, ! が役立つのは間違いない。

$_ にマッチさせる

/regex/
m:regex:

string にマッチさせる

string =~ /regex/
string =~ m:regex:

$_ の文字列置換

s/regex/new/
s:regex:new:

string の文字列置換

string =~ s/regex/new/
string =~ s:regex:new:

特殊なメタキャラクタ

^, $

  • 行頭、末尾にマッチ

.

  • ニューライン以外の任意の文字にマッチ

[chars]

  • chars に含まれる任意の1文字にマッチ
  • chars 内のバックスラッシュ付き英数字以外のメタキャラクタは、リテラル扱い

[^ chars]

  • chars に含まれない任意の1文字にマッチ
  • メタキャラクタの扱いは [chars] と同様

[char1-char2]

  • char1char2 の間に入る任意の文字にマッチ
  • char1, char2 を含む。

$&

  • 最後にマッチした内容を保持
  • 'Foo' =~ /^[A-Z]/ なら $& は F

\

  • メタキャラクタに使ったり、エスケープに使う

\b

  • 単語の区切りにマッチする
  • 'abc def' にマッチさせたいときに、'Zabc def' にマッチしないよう、'babc def' と書いておく。
  • アルファベットは、単語構成文字クラスなので、スペースや!は、b にマッチするが、Zはマッチしない。

\n

  • ニューライン

\r

  • キャリッジリターン文字
  • カーソルを行頭に戻す

\t

  • タブ

\f

  • フォームフィード
  • 改ページ

\e

  • エスケープ文字

\NNN

  • 8進数が NNN となる文字
  • 例えば、040 はスペース

備考

8進数や16進数を調べるには、man ascii

\xNN

  • 16進数が NN となる文字
  • 例えば、x20 はスペース

\cX

  • X によって表される制御文字
  • 例えば、 cC はCtrl-C

\Q, \E

  • メタキャラクタを文字として見せたい部分を、\Q ... \E で囲む

POSIX の文字クラスとショートカットメタキャラクタ

文字クラス ショートカットメタキャラクタ 説明
[a-zA-Z0-9_] \w 単語構成文字
[^a-zA-Z0-9_] \W 非単語構成文字
[\040\t\r\n\cJ\cL] \s 空白文字
[^\040\t\r\n\cJ\cL] \S 非空白文字
[0-9] \d 数字
[^0-9] \D 数字以外の文字

マッチ修飾子

/RE/i や m%RE%xs, s/RE/new/e など、最後に修飾子をいくつかつけて、マッチングの動作を変更させることができる。

マッチ修飾子
修飾子 説明
i
大文字小文字の違いを無視
x
拡張モード
REフィールドに空白文字とコメントを許す
s
シングルラインモード
. をニューラインにもマッチさせる
m
マルチラインモード
^, $ を文字列の絶対的な先頭、末尾でなく、ターゲット文字列中の行の先頭、末尾にマッチさせる
g
すべてのマッチを、スカラーコンテキストかリストコンテキストかによって、連続的もしくは集合的に返す
e
置換の時に使う。 new を Perl のコードとして評価して、RE にマッチしたものをその結果で置き換える。

その他の構文

選択、グループ化、キャプチャ、後方参照
構文 説明
X|Y|Z
X, Y, Zのいずれかにまっち
(X)
グループ化とキャプチャ
a(X|Y)bc や (XY)+ といった感じで使う
\1, \2, ...
後方参照。検索文字列フィールドで使用
$1, $2, ...
後方参照。検索文字列フィールド以外で使用

量指定子

量指定子
構文 説明
X*
0回以上の繰り返し
X+
1回以上の繰り返し
X?
0 または 1回の出現
X{min, max}
min回以上max回以下の繰り返し
X{min, }
min回以上の繰り返し
X{count}
count回の繰り返し
X{, max}
max回以下の繰り返し
REP?
量指定子の直後に ? をつけると、最短マッチ
例えば、.*? という風な。

以下は、Perl で正規表現を扱うときのコツ

grep

grep -v

  • perl で grep -v のように、マッチしないものを表示させるのは、次のように行う。
    # 空行以外を表示
    perl -wnl -e '/^$/ or print;' file
    
    このように or を使うと便利。

grep -l

# foo にマッチするもののファイル名を表示
# close することで、マッチした後は探索しない。
perl -wnl -e '/\bfoo\b/ and print $ARGV and close ARGV;' file

カスケードフィルタ

  • シェルで grep "regex1" file | grep "regex2" とやることに相当

    # foo という単語と bar という単語を含む行を見つける
    perl -wnl -e '/\bfoo\b/ and /\bbar\b/ and print;' file
    

コンテキスト表示

  • 段落モード -00 と ファイルモード -0777 を上手く使う

  • /regex/s も上手く使うと良い

  • 行をまたがるマッチングを行うとき、間にどんな文字を許すか考える必要がある。ニューラインについて言えば、

    • マッチ修飾子の s を使って . をニューラインにマッチさせる
    • [\t\n]+ や [_\s]+ というように、明示的に指定したり、[^aiueo]+ などを使う
    • s を使う

sed

置換のデリミタ

  • 対応する括弧も使用可能

    s/.../.../
    s|...|...|
    s{...}{...}, s(...)(...)
    

行指定置換, コンテキストアドレス

  • sed では、次のように、置換の構文の前に、アドレスを指定して、置換する場所を制限できる。

    # 2行目のみ置換
    2s/regex/new/g
    # 2〜5行目のみ置換
    2,5s/regex/new/g
    # 行頭が fff の行について置換
    /^fff/s/regex/new/g
    
  • これを Perl では、行数に関する条件式で書く必要がある

    # 2行目のみ置換
    perl -wpl -e '$. == 2 and s/regex/new/g;' file
    # 2〜5行目のみ置換
    perl -wpl -e '2 <= $. and $. <= 5 and s/regex/new/g;' file
    # 行頭が fff の行について置換
    perl -wpl -e '/^fff/ and s/regex/new/g;' file
    

後方参照

  • sed では、キャプチャするときに、 ? を使えなかった。 Perl では、? を使える。

  • sed では、どこでも 1, 2, ...で参照したが、Perlでは 1, 2, ... と $1, $2, ... とどこから参照するかによって異なる。

    # Mr か Mr. を見る
    perl -wnl -e 's/(Mr.?) (Fo[oa])/$1 Bar $2/g;' file
    

計算結果で置換

  • sed では、置換文字列フィールドに計算結果を入れることが難しかった。(できるか知らない。)

  • perl では、簡単にできる。マッチ修飾子の e が必要。

    perl -wnl -e 's/\d+/$& * 2.1/ge;' file
    

AWK

フィールドアクセス

  • AWK では、フィールドアクセスが便利

    # スペースorタブ区切りのフィールドの順番を入れ替える
    awk '{ print $2, $1}' file
    
  • Perl で似たようなことをやるには、2つ方法がある。

    1. コマンドラインオプション -a (と合わせて、-F)を使う

    2. 自分で各フィールドを変数に代入する

      フィールドアクセス
      構文 コメント
      ($A, $B)=@F; それぞれの変数にセット
      ($A, undef, $B)=@F; 第2フィールドは変数に入れない
      $numfields=@F; レコードのフィールド数を格納

パターン範囲

パターン範囲
演算子 構文 コメント
.. regex1 .. regex2
regex1を含む最初のレコードからregex2を含む最初のレコードまでの範囲
一旦regex1とregex2の組が見つかると次のregex1を見つけるまで、無視
regex1とregex2が同じレコードにある場合もマッチ。
... regex1 ... regex2
.. とほぼ同じ。
ただし、regex2はregex1の次の行以降から探す。

find

ファイル属性テスト

ファイル属性テスト (○ は属性に対応する文字)
構文 コメント
-○ filename filename が○という属性を有していることをテスト
! -○ filename filename が○という属性を有していないことをテスト
-○ $_ が○という属性を有していることをテスト
! -○ $_ が○という属性を有していないことをテスト
ファイル属性と対応する演算子
ファイル属性 演算子
通常ファイル -f
ディレクトリ -d
シンボリックリンク -l
名前付きパイプ -p
キャラクタ -c
ブロック -b
ソケット -S
-z
空でない -s
実UID/GIDで読取り可 -R
実UID/GIDで書込み可 -W
実UID/GIDで実行可 -X
実UIDが所有 -O
実効UID/GIDで読取り可 -r
実効UID/GIDで書込み可 -w
実効UID/GIDで実行可 -x
実効UIDが所有 -o
指定のUID/GIDが所有 stat
setuid -u
setgid -g
sticky -k
テキスト -T
バイナリ -B
別のファイルより新しい stat
別のファイルより後にアクセスされた stat
リンクの数 stat
inode番号 stat