cl irregsexp - lisp-cookbook-ja/common-lisp GitHub Wiki

正規表現 cl-irregsexp

CLiki:cl-irregsexpでは正規表現をS式で表現します。多くの正規表現のエンジンと異なり、マッチが失敗した時点で探索が終了します。そのため、任意の位置にあるパターンを探す場合、明示的に変数を指定して、マッチしない文字を読み飛ばす必要があります。

パターンの例

;; aにマッチする
(cl-irregsexp:if-match-bind (_ "a") "abc")
(cl-irregsexp:if-match-bind (_ "a") "bca")
(cl-irregsexp:if-match-bind (_ "a") "cab")
(cl-irregsexp:if-match-bind (_ #\a) "abc")
(cl-irregsexp:if-match-bind (_ #\a) "bca")
(cl-irregsexp:if-match-bind (_ #\a) "cab")
;=> T

;; itにマッチする
(cl-irregsexp:if-match-bind (_ "it") "hit")
(cl-irregsexp:if-match-bind (_ "it") "its")
(cl-irregsexp:if-match-bind (_ #\i #\t) "hit")
(cl-irregsexp:if-match-bind (_ #\i #\t) "its")
;=> T

;; 任意の文字にマッチする
(cl-irregsexp:if-match-bind ((char)) "abc")
;=> T

;; マッチした任意の文字をanyに束縛する
(cl-irregsexp:if-match-bind ((any (char))) "abc" any)
;=> "a"

;; 任意の3文字にマッチする
(cl-irregsexp:if-match-bind ((char) (char) (char)) "abc")
;=> T

;; マッチした任意の3文字をそれぞれxとyとzに束縛する
(cl-irregsexp:if-match-bind ((x (char)) (y (char)) (z (char)))
                            "abc"
                            (concatenate 'string x y z))
;=> "abc"

;; アルファベットにマッチする
(cl-irregsexp:if-match-bind ((or (- #\a #\z) (- #\A #\Z))) "abc")
;=> T

;; マッチした1文字以上のアルファベットをwordに束縛する
(cl-irregsexp:if-match-bind ((word (+ (or (- #\a #\z) (- #\A #\Z))))) "abc" word)
;=> "abc"

;; aとbとcのいずれかにマッチする
(cl-irregsexp:if-match-bind ((or "a" "b" "c")) "abc")
(cl-irregsexp:if-match-bind ((or #\a #\b #\c)) "abc")
;=> T
(cl-irregsexp:if-match-bind ((or "a" "b" "c")) "def")
(cl-irregsexp:if-match-bind ((or #\a #\b #\c)) "def")
;=> NIL

;; aとbとc以外にマッチする
(cl-irregsexp:if-match-bind ((not (or "a" "b" "c"))) "abc")
(cl-irregsexp:if-match-bind ((not (or #\a #\b #\c))) "abc")
;=> NIL
(cl-irregsexp:if-match-bind ((not (or "a" "b" "c"))) "def")
(cl-irregsexp:if-match-bind ((not (or #\a #\b #\c))) "def")
;=> T

;; 行の最初のaにマッチする
(cl-irregsexp:if-match-bind ("a") "abc")
(cl-irregsexp:if-match-bind (#\a) "abc")
;=> T
(cl-irregsexp:if-match-bind ("a") "bca")
(cl-irregsexp:if-match-bind (#\a) "bca")
;=> NIL

;; 行の最後のcにマッチする
(cl-irregsexp:if-match-bind (_ "c" (last)) "abc")
(cl-irregsexp:if-match-bind (_ #\c (last)) "abc")
;=> T
(cl-irregsexp:if-match-bind (_ "c" (last)) "aaa")
(cl-irregsexp:if-match-bind (_ #\c (last)) "aaa")
;=> NIL

;; 整数にマッチする
(cl-irregsexp:if-match-bind ((i (integer))) "01234" i)
;=> 1234
(cl-irregsexp:if-match-bind ((i (integer))) "abcde" i)
;=> NIL

;; 浮動小数点数にマッチする
(cl-irregsexp:if-match-bind ((f (float))) "3.14" f)
;=> 157/50
(cl-irregsexp:if-match-bind ((f (float))) "a.bc" f)
;=> NIL

基本的なパターンマッチ

;; 戻り値はbody部分によって変わる
(cl-irregsexp:match-bind ((b (or (float) (integer))) (:? #\^ (e (integer))))
    "3.14^10"
  (values (read-from-string b) e))
;=> 3.14
;   10

;; マッチしない場合はエラー
(cl-irregsexp:match-bind ((a #\a)) "b" a)
;>> Error: #<CL-IRREGSEXP:MATCH-FAILED #x1918B48E>

条件式

パターンがマッチしたかどうかで処理を分岐します。

;; then部とelse部は省略でき、それぞれtとnilを返す
(cl-irregsexp:if-match-bind (#\a) "a")
;=> T

;; 応用例:十六進数を読み込む
(cl-irregsexp:if-match-bind ("0x" (hex (+ (or (- #\a #\f) (- #\0 #\9)))) (last))
                            "0xffff"
                            (values (read-from-string (format nil "#x~A" hex)))
                            (error "syntax error"))
;=> 65535

パターンの置換

;; 最初にマッチした部分を置換する
(cl-irregsexp:match-replace-one "<<<"
  (#\< "&lt;"))
;=> "&lt;<<"
;   3

;; マッチする部分をすべて置換する
(cl-irregsexp:match-replace-all "<<<"
  (#\< "&lt;"))
;=> "&lt;&lt;&lt;"
;   6

パターンによる分割

(cl-irregsexp:match-split #\: "a:b:c")
;=> ("a" "b" "c")

参考文献