サンプルのiniファイルはこのようになっています。
[Section1] Key1=Value1 Key2=Value2 [Section2] Key1=Value1 [Section3]
プログラム本体は以下のとおりです。
;; inifile.l (defun read-lines (input) (loop as line = (read-line input nil nil) while line collect line)) (defun sectionp (line) (and (stringp line) (<= 2 (length line)) (eq #\[ (char line 0)) (eq #\] (char line (1- (length line)))))) (defun keyvaluep (line) (and (stringp line) (<= 3 (length line)) (find #\= line) (< 0 (position #\= line)))) (defun strip-section (line) (if (not (sectionp line)) line (subseq line 1 (1- (length line))))) (defun split-keyvalue (line) (if (not (keyvaluep line)) line (list (subseq line 0 (position #\= line)) (subseq line (1+ (position #\= line)))))) (defun convert-to-alist (alist line) (cond ((sectionp line) (cons (list (strip-section line)) alist)) ((keyvaluep line) (cons (append (car alist) (list (split-keyvalue line))) (cdr alist))) (t alist))) (defun ini-assoc (section key alist) (car (last (assoc key (cdr (assoc section alist :test 'string-equal)) :test 'string-equal)))) ;; 以下実行部 (setf ini-alist (reduce 'convert-to-alist (read-lines *standard-input*) :initial-value '())) (format t "~A~%" ini-alist) (format t "~A ~A = ~A~%" "Section2" "Key1" (ini-assoc "Section2" "Key1" ini-alist)) (format t "~A ~A = ~A~%" "SECTION1" "KEY2" (ini-assoc "SECTION1" "KEY2" ini-alist))
実行すると、以下のように出力します。
$ cat sample.ini | clisp inifile.l ((Section3) (Section2 (Key1 Value1)) (Section1 (Key1 Value1) (Key2 Value2))) Section2 Key1 = Value1 SECTION1 KEY2 = Value2
工夫したところは、関数"ini-assoc"でstring-equalを使用し、大文字と小文字を区別し内容にしたところです。
alistで返すことが目標だったので、パフォーマンスはよくありません。
今までの書き方であれば、DictionaryやMapを更新しまくるプログラムを書いてました。reduceに渡す関数を実装するにあたり、「新しいリストを返す」という発想に辿り着くまで時間がかかりました。