グロブの展開
30分プログラム、その176。[n-m]という形のグロブを展開する。
例えば、zshだと
$ rm tmp[0-2]
とやるとtmp0、tmp1、tmp2がまとめて削除できる。
このような文字列の展開をSchemeでやってみる。
使い方
gosh> (expand-glob "a[0-3].txt") ("a0.txt" "a1.txt" "a2.txt" "a3.txt") ;; 最初に0がついている場合はそれを保持する gosh> (expand-glob "a[00-03].txt") ("a00.txt" "a01.txt" "a02.txt" "a03.txt") ;; 複数[n-m]がある場合は両方展開する ;; 先に登場したものが先に展開される gosh> (expand-glob "a[0-2][0-2].txt") ("a00.txt" "a01.txt" "a02.txt" "a10.txt" "a11.txt" "a12.txt" "a20.txt" "a21.txt" "a22.txt") gosh>
ソースコード
#! /opt/local/bin/gosh ;; -*- mode:scheme; coding:utf-8 -*- ;; ;; glob_expand.scm - ;; ;; Copyright(C) 2007 by mzp ;; Author: MIZUNO Hiroki <hiroki1124@gmail.com> ;; http://mzp.sakura.ne.jp/ ;; ;; Timestamp: 2007/11/07 20:31:21 ;; ;; This program is free software; you can redistribute it and/or ;; modify it under the same terms as Scheme itself. ;; (use srfi-1) ;; 文字列版のrange。文字列の幅を指定できる ;; ;; e.g. (range 0 3 1) -> '("0" "1" "2" "3") ;; e.g. (range 0 3 2) -> '("00" "01" "02" "03") (define (range from to width) ;; format用の文字列を生成する (let1 f (format #f "~~~d,'0d" width) ; e.g. "~3,'0d" (map (pa$ format #f f) (iota (- to from -1) from)))) ;; 文字列中の[n-m]を展開する (define (expand-glob str) (let1 m (rxmatch #/\[(\d+)-(\d+)\]/ str) (if m (let ((from (rxmatch-substring m 1)) (to (rxmatch-substring m 2)) ;; 後続の文字列の[n-m]を展開しておく (after (expand-glob (rxmatch-after m)))) (append-map (lambda (n) (map (pa$ string-append (rxmatch-before m) n) after)) (range (string->number from) (string->number to) (string-length from)))) (list str))))