sed/正規表現メモ

sedについて

改行コードを変更したい

  • 改行コードを\nから\r\nに(つまりLinux(LF)からWindows(CR+LF)に)変換したい
  • sed -i 's/\n/\r\n/' file はダメで、sed -i 's/$/\r/' file とする必要がある

パターンスペース

  • $(行末)を\r(CR)で変換しているのに、その結果が\r\n(CR+LF)になっている点が不思議だが、これはパターンスペースのしわざである
  • sedは読み込んだ行の行末にある改行を削除してパターンスペースと呼ばれるバッファに格納したうえでテキスト処理をし、最後にパターンスペースの内容に改行をつけて出力する」from http://shantiworks.info/2012/08/10/sedで改行を含む複数行の文字列を置換/
  • パターンスペース上で$\rに変換したあと、出力する際に\nを付けるため、\r\nになる

POSIX sedGNU sed

(man sed より)
     -i extension
             Edit files in-place, saving backups with the specified extension.  If a zero-length
             extension is given, no backup will be saved.  It is not recommended to give a zero-
             length extension when in-place editing files, as you risk corruption or partial content
             in situations where disk space is exhausted, etc.

使用例 (POSIX sed)

$ cat test.txt 
aaa
bbb
ccc
$ sed -e 's/\(b\{2\}\)/\1zzz/g' -e 's/\(c\{2,\}\)/xxx\1/g' test.txt 
aaa
bbzzzb
xxxccc
  • マッチした行のみ処理を実行して表示
sed -n 's/\(bbb\)/\1?/p' test.txt 
bbb?
  • マッチした行に、改変した行を加える場合
$ sed '/bbb/p; s/bbb/zzz/g' test.txt 
aaa
bbb
zzz
ccc
# sedはデフォルトでマッチしない行を出力し、マッチした行は処理を実行する
# pコマンドでその行を表示し、sコマンドでその行を置換している
  • 1行目/最終行のみ/以外を表示
$ sed -n 1p test.txt 
aaa
$ sed -n \$p test.txt 
ccc
# nオプションでマッチした行のみ表示する

$ sed 1d test.txt 
bbb
ccc
$ sed \$d test.txt 
aaa
bbb

正規表現について

  • 考え方として、文字列は一つ以上の行から形成される
  • ^$は行の先頭と末尾にマッチし、¥A¥Zは文字列の先頭と末尾にマッチする
  • なお、ピリオドは改行コードにマッチしない

m修飾子

  • m修飾子を用いない場合、文字列は一つの行としてみなされ、^¥A$¥Zは同じ意味になる
  • m修飾子を用いる場合(//mのように指定する)、文字列は(文字列でありながら)改行コードで区切られた複数の行としてみなされる

  • Rubyのデフォルトは後者である。では、Rubyのm修飾子は何を意味しているのか?

    • Ruby)m修飾子を用いる場合、.が改行コードにマッチする
    • Ruby以外)s修飾子を用いる場合、.が改行コードにマッチする
  • c.f. 正規表現によるバリデーションでは ^ と $ ではなく \A と \z を使おう | 徳丸浩の日記

補足

  • []の中に.*を入れた場合はメタキャラクタではなくリテラルとなり、文字通り.*にしかマッチしない