概要

CL-PPCREはPerl互換の正規表現ライブラリです。

このページでは、CL-PPCREの使い方を簡単に紹介します。

CL-PPCREはASDFを利用してロードするため、QuicklispまたはASDFであらかじめロードしておいてください。

(asdf:load-system :cl-ppcre)
; => T

また、ライブラリ名を付けずに直接アクセスするには、use-package関数やdefpackageマクロの:useオプションでパッケージの継承をしておいてください。ここではパッケージが継承されている前提で説明します。

(use-package :ppcre)
; => T

なお、CL-PPCREはCL-INTERPOLというライブラリとの相性が良く、頻繁に併用されます。そちらも合わせて参照してください。

検索: scan, scan-to-strings

正規表現で最も用いるのは「検索」です。CL-PPCREにはいくつかの検索機能があります。

まず、最もシンプルに検索を行うにはscan関数を利用します。

(defparameter *data* "aaa<h1>bbb</h1>ccc")
; => *DATA*

(scan "<h1>.*</h1>" *data*)
; => 3 ;
;    15 ;
;    #() ;
;    #()

検索した正規表現中の特定の文字列だけを抽出したい場合は、正規表現の中にグルーピングのカッコを付けます。

(scan "<h1>(.*)</h1>" *data*)
; => 3 ;
;    15 ;
;    #(7) ;
;    #(10)

検索をかけて、マッチした文字列を使いたい場合は文字列中のインデックス(要素番号)を得るよりも文字列そのものを得た方が便利なことが多いです。

(scan-to-strings "<h1>(.*)</h1>" *data*)
; => "<h1>bbb</h1>" ;
;    #("bbb")

このような使い方が多い場合は、以下のような関数を定義しておけば返り値として文字列を簡単に取得できます。

(defun get-regex (regex string)
  (multiple-value-bind (x y)
      (scan-to-strings regex string)
    (svref y 0)))
; => GET-REGEX

(get-regex "<h1>(.*)</h1>" *data*)
; => "bbb"

なお、scan関数とscan-to-strings関数には、全ての要素を検索できるall-matches関数とall-matches-as-string関数もありますので、適宜活用してください。

分割: split

正規表現で便利なのは検索だけではありません。「分割」も正規表現が力を発揮する領域です。

なお、正規表現を用いず、単に文字で文字列を分割する場合はsplit-sequenceというライブラリを用いることが一般的です。そちらはSpec Guideの第16章「文字列」で紹介しているので、そちらを参照してください。

正規表現で分割する場合はsplit関数を用います。

(split "/|:|\\s" "2017/12/31 12:34:56")
; => ("2017" "12" "31" "12" "34" "56")

Perlと異なるのは、Common Lispでは\が文字を表す特殊な役割を担っているため、文字クラスを示すには\\のように2つ並べる必要がある点です。しかし、それ以外はPerlの正規表現と同様に使うことができ、文字列処理では大いに重宝します。

置換: regex-replace, regex-replace-all

最後に、正規表現を使うと便利なのは文字列の「置換」です。

置換を行うにはregex-replace関数を用いますが、置換は検索と異なり、常に全ての対象正規表現を置換することが多いかと思いますので、その複数形であるrepex-replace-all関数を紹介します。

(regex-replace-all "[abc]" "apple banana cookie" "*")
; => "*pple **n*n* *ookie" ;
;    T

とても簡単です。

CL-PPCREは本家のPerlよりも高速と言われるほど洗練されたライブラリです。文字列処理を行う場合は常にロードしておき、積極的に活用してください。


Copyright (C) 2017- Satoshi Yamamoto (Shoty).
Some rights reserved.