文字列を検索する

文字列を検索する

いわゆる正規表現によるマッチングです.

#/regexp-spec/

とすることで,正規表現を表現することができます.他の言語上で正規表現を使ったことがあれば,違和感ないでしょう.

パターンが含まれるかどうか

空白文字もしくはタブを検索する例.
マッチした場合には正規表現オブジェクトを,マッチしなかった場合には#fを返します.

(#/[ \t]/ "a c")
  =>#<<regmatch> 0x51dae0>
(#/[ \t]/ "abc")
  =>#f

マッチの詳しい情報を得る

正規表現オブジェクトそのものを評価すると,マッチした文字列が得られます.
'beforeや'afterではマッチ前後の文字列が得られます.

(let1 match (#/abc/ "xxxabcabcabcxxx")
  `(,(match 'before)
    ,(match)
    ,(match 'after)))
  =>("xxx" "abc" "abcabcxxx")

文字列中に複数マッチする

1つの文字列に対して複数箇所マッチさせる手続きはなさそう(?)なので,再帰させます.

(define (scan-match re str)
  (let1 match (re str)
    (if match
	(cons match (scan-match re (match 'after)))
	'())))

(define (scan-match-string re str)
  (map (lambda (m) (m)) (scan-match re str)))

(scan-match-string #/[あ-ん]+/ "あ\n aadかきe\ne さ0\n0aた\n ii な\n")
  => ("あ" "かき" "さ" "た" "な")

パターンが最初に出現する位置

rxmatch-startを使います.カウントする単位はバイトではなくて文字数のようです.

(rxmatch-start (#/abc/ "xxxabcabcabcxxx"))
  =>3
(rxmatch-start (#/abc/ "ここからabcabcabcここまで"))
  =>4

パターンが最後に出現する位置

残念ながら,rxmatch-endを使うとうまくいきません.rxmatch-endは最初にマッチした箇所の最後の文字位置を返します.

(rxmatch-end (#/abc/ "xxxabcabcabcxxx"))
  =>6 ; 違う!

では,どうしたらいいのでしょう...
ここではrxmatch-startとendを組み合わせて数え上げます.

(define (rxmatch-last re str)
  (define (rxmatch-ends ms)
    (if (pair? (cdr ms))
	(cons (rxmatch-end (car ms)) (rxmatch-ends (cdr ms)))
	(list (rxmatch-start (car ms)))))
  (let1 matches (scan-match re str)
    (fold + 0 (rxmatch-ends matches))))

(rxmatch-last #/abc/ "xxxabcabcabcxxx")
  =>9

パターンを含む行のみを処理する

"\n"による改行を含む文字列において,パターンを含む行を取り出します.
string-splitで分割してから,マッチする行をfilter-mapで抽出します.

(use srfi-1)
(define (string-grep re lines)
  (filter-map (lambda (line) (and (re line) #`",line\n"))
	      (string-split lines "\n")))

(string-grep #/[あた]/ "あ\n aadかきe\ne さ0\n0aた\n ii な\n")
  =>("あ\n" "0aた\n")