LoginSignup
3

posted at

シェルスクリプトの世界から基本正規表現(BRE)をなくそう!

はじめに

UNIX コマンドが対応している正規表現には、基本正規表現 (BRE) と拡張正規表現 (ERE) の二種類があります。誰もがよく知っている正規表現は拡張正規表現(の拡張版)です。基本的には基本正規表現はもう忘れていいです。ならぜなら、一番の懸念点であった sed コマンドの拡張正規表現対応 (sed -E) が POSIX Issue 8 で標準化されることになったからです。

シェルスクリプトでよく使う awk、grep、sed が拡張正規表現に対応したことで、基本正規表現はほぼ不要になりました。拡張正規表現に対応していないのは、あまり必要でない expr や、シェルスクリプトでほとんど使われない ed、ex、more ぐらいです。

とはいえ expr で基本正規表現は使うと言えば使います。で、ふと思ったのですが、基本正規表現と拡張正規表現はエスケープする文字が異なるだけで機能はほとんど同じです(下記参考リンク参照)。それなら拡張正規表現を基本正規表現に変換してやれば、基本正規表現を使う必要はないですよね?ということで実装してみました。これでもう基本正規表現のことは忘れてしまうことが出来ます。

参考リンク

実装(サンプル)

注意 思いつきでざっくり実装しただけのでテストは不十分です。バグがあるかもしれません。

#!/bin/sh

set -eu

# 拡張正規表現(ERE)から基本正規表現(BRE)への変換関数
ere2bre() {
  set -- "$1" "$2" ""
  while [ "$2" ]; do
    case $2 in
      "\\+"* | "\\?"* | "\\|"* | "\\{"* | "\\}"* | "\\("* | "\\)"*)
        set -- "$1" "${2#?}" "$3"
        set -- "$1" "${2#?}" "$3${2%"${2#?}"}"
        ;;
      "+"* | "?"* | "|"* | "{"* | "}"* | "("* | ")"*)
        set -- "$1" "${2#?}" "$3\\${2%"${2#?}"}"
        ;;
      *) set -- "$1" "${2#?}" "$3${2%"${2#?}"}" ;;
    esac
  done
  eval "$1=\$3"
}

# 拡張正規表現対応させるための expr のラッパー
expr() {
  if [ "${2:-}" = ":" ]; then
    ere2bre bre "$3"
    set -- "$1" "$2" "$bre"
  fi
  command expr "$@"
}

# 拡張正規表現で呼び出せる
expr "$(id)" : "uid=([0-9]*)\("
echo "-----"

example() {
  ere="$2"; ere2bre bre "$ere"
  echo "=== $ere : $bre ==="
  printf '%s\n' "$1" | grep --color -E "$ere"
  printf '%s\n' "$1" | grep --color "$bre"
}

example 'a\b' 'a\\b'
example 'a(b' 'a\(b'
example 'ab' 'a(b)'
example 'a{b}' 'a\{b\}'
example 'ab' 'a.*'
example 'ac' 'ab?c'
example 'abc' 'ab?c'
example 'a' '(a|b)'
example 'aca' '(a|b)c\1'
example 'az' 'a\z'

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
3