サンプルの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に渡す関数を実装するにあたり、「新しいリストを返す」という発想に辿り着くまで時間がかかりました。
0 件のコメント:
コメントを投稿