逆引きxyzzy lisp(正規表現) - circleratio/xyzzy GitHub Wiki

目次

マッチ

バッファを正規表現とマッチさせる

(scan-buffer "[a-z]\\{3\\}" :regexp t)
=> nil

オプション指示をしなければ、現在のカーソル位置からバッファ末尾までを前方に検索する。

文字列を正規表現とマッチさせる

(string-match "a.c" "-abc")
=> 1

Common Lisp にはない関数.

現在のカーソル位置でマッチさせる(前方にマッチ)

(defun lookup (regexp)
  (interactive "sRegxep: ")
  (if (looking-at regexp)
      (message "found")
    (message "not found")))

現在のカーソル位置でマッチさせる(後方にマッチ)

(defun lookup-backward (regexp)
  (interactive "sRegxep: ")
  (save-excursion
    (save-restriction
      (narrow-to-region (point-min) (point))
      (goto-char (point-min))
      (if (scan-buffer (format nil "~A\\'" regexp)
		       :regexp t :case-fold nil)
	  (message "found")
	(message "not found")))))

マッチした文字列を取り出す

バッファの場合も文字列の場合も同じ。

(scan-buffer "[a-z]+" :regexp t)
=> t

(match-string 0)
=> "abc"

マッチした範囲を取得する

バッファの場合も文字列の場合も同じ。

(scan-buffer "[a-z]+" :regexp t)
=> t

(match-beginning 0)
=> 142

(match-end 0)
=> 147

検索結果の保存,復元

scan-buffer で検索を行った時点の状態を保持できる. 復元を行った後には,match-string, match-beginning, match-end, replace-match を使える.

これにより,複数の検索結果を使った処理を楽に書ける.

(scan-buffer "[a-z]+" :regexp t)
=> t

(setq md (match-data))
=> #(38 39 nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)

(store-match-data md)
=> t

繰り返し文字とマッチさせる

メタ文字の *, +, ? を使う。

"*" は直前の正規表現の 0 回以上の繰り返しにマッチする。

(string-match  "a*c" "abc") => 2
(string-match  "a*c" "ac") => 0
(string-match "a*c" "aaaaaac") => 0
(string-match  "a*c" "c") => 0
(string-match "a*c" "abcccccc") => 2
(string-match "a*c" "abd") => nil

"+" は直前の正規表現の 1 回以上の繰り返しにマッチする。

(string-match  "a+c" "abc") => nil
(string-match  "a+c" "ac") => 0
(string-match "a+c" "aaaaaac") => 0
(string-match  "a+c" "c") => nil
(string-match "a+c" "abcccccc") => nil
(string-match "a+c" "abd") => nil

"?" は直前の正規表現の 0回または 1 回の繰り返しにマッチする。

(string-match  "a?c" "abc") => 2
(string-match  "a?c" "ac") => 0
(string-match "a?c" "aaaaaac") => 5
(string-match  "a?c" "c") => 0
(string-match "a?c" "abcccccc") => 2
(string-match "a?c" "abd") => nil

数字だけ、アルファベットだけとマッチさせる

文字クラスを使う。

(string-match "[0-9]" "a") => nil
(string-match "[0-9]" "1") => 0

(string-match "[A-Z]" "M") => 0
(string-match "[A-Z]" "8") => nil

[]内で ^ を使うと、「それ以外」を表現できる。

(string-match "[^0-9]" "1") => nil
(string-match "[^A-Z]" "M") => nil

改行コードを含む文字列にマッチさせる

.は「改行文字を除く任意の1文字にマッチ」なので注意。 グルーピングを使うとよい。

(string-match "abc.*xyz" "abcdefg\nvwxyz") => nil

(string-match "abc\\(.\\|\n\\)*xyz" "abcdefg\nvwxyz") => 0

(match-string 0)
=> "abcdefg
   vwxyz"

n番目のマッチを見つける

正規表現のグルーピングと match-string を使う。

match-string の引数は次のような意味を持つ。 :0: 正規表現に一致する文字列 :1-9:正規表現中のn番目のカッコに対応する文字列

(string-match "1\\(.\\)3\\(.\\)5\\(.\\)" "123456") => 0

(match-string 0) => "123456"
(match-string 1) => "2"
(match-string 2) => "4"
(match-string 3) => "6"

(string-match "\\([a-z]+\\),\\([0-9-]+\\),\\([^ ]+\\)" "tf,000-111-2222,Japan") => 0
(match-string 1) => "tf"
(match-string 2) => "000-111-2222"
(match-string 3) => "Japan"

置換

正規表現を使ってバッファ中の文字列を置き換える

(replace-buffer "[a-z]\\{3\\}" "OK" :regexp t)
=> 1

検索にマッチしたバッファ中の文字列を別の文字列で置換する

(scan-buffer "[a-z]+" :regexp t)
=> t

(replace-match "xyz")
=> t

分割

パターンで区切られたレコードを読む

(split-string "a,b,c/d" "[,/]")
=> ("a" "b" "c" "d")

マッチした文字列を全て抜き出してリストへ格納する

(defun string-scan (regexp str)
  (if (string-match regexp str)
      (cons (subseq str (match-beginning 0) (match-end 0))
	    (string-scan regexp (subseq str (match-end 0) (length str))))
    nil))

(string-scan "\\([^ ]+\\):\\([0-9-]+\\)" "inu:000-111-2222 saru:111-222-3333 gomi kiji:222-333-4444")
=> ("inu:000-111-2222" "saru:111-222-3333" "kiji:222-333-4444")

バッファ処理

バッファ内の特定のパターンに対して処理を行う

(defun process-pattern (str)
  (interactive "sPattern: ")
  (goto-char (point-min))
  (while (scan-buffer str :regexp t)
    (msgbox "~A:~A" (point) (match-string 0))
    (forward-char)))

次の書き方ではうまく動作しない.

scan-buffer に no-dup を指示すると「ポイントの次の位置」を基点にするため,バッファ先頭にあるパターンにはマッチしないため.

(defun process-pattern (str)
  (interactive "sPattern: ")
  (goto-char (point-min))
  (while (scan-buffer "aaa" :no-dup t :regexp t)
    (msgbox "~A:~A" (point) (match-string 0))))

正規表現をコンパイルする

あまり効果はないので,よほどのことがない限り,使う必要なし.

(scan-buffer (compile-regexp "[a-z]+") :regexp t)
=> t

正規表現に含まれるメタ文字をエスケープする

(regexp-quote "[abc](defg)*+")
=> "\\[abc](defg)\\*\\+"
⚠️ **GitHub.com Fallback** ⚠️