落穂ひろい
昨日は、くそ暑い地を離れて、赤城山へ行ってきた。上は、気温20度の別天地。適当な格好で 行ったから、じっとしてると少々寒いぐらいだった。こういう所なら、気分良く読書等が 出来るかな?
帰りには、以前入った事がある、旨い蕎麦屋によってきた。 帰ってきて調べてみたら桑風庵と言う 有名な所だったらしい。たっぷりと田舎蕎麦を食べて、満足になりました。
前回のプログラムで語り尽くせなかった事
scheme != (ocaml | Haskell) と言う事で、場合を尽くしてなくても、エラーにならずに、素通り してた部分がありました。
(cond ((char-set-contains? #[[:digit:]] (car cl)) #`"<NUMK VAL=,|str|>") ((char-set-contains? #[[:alpha:]] (car cl)) (csub cl ALPHA)) ((char-set-contains? #[[:punct:]] (car cl)) (csub cl PUNCT)) (else str))))
の所です。いわゆる、コントロール文字が積極的にチェックされてないため、else句に 落ちてきて、それを食べた、gsayがゲロを吐いてしまいます。(mecabで、フィルター されると思ってましたが、すり抜けてしまう文字がありました。) ここは、ちゃんと、コントロール文字かチェックすべきですね。
((char-set-contains? #[[:cntrl:]] (car cl)) "どくもじ")
原因追求
えっと、POSIXの表現って、よく知らなかったりします。よい機会なので、どうなって いるか調べてみました。Cが基本なはずですが、マクロ名を思い出せなかったので、gaucheに 教えてもらう事にしました。いきなり
[sakae@nil ~/Gauche-0.8.14/src]$ grep punct * char.c: } else if (strncmp(name, ":punct:", 7) == 0) { char.c: if (ispunct(code)) MASK_SET(CS(SCM_CHAR_SET_PUNCT), code); [sakae@nil ~/Gauche-0.8.14/src]$ vi char.c
こうして、おお、そうだそうだ。ctype.h ね、と、思い出す始末。そのヘッダー ファイル経由で、やっと、ispunct を思い出し
DESCRIPTION The ispunct() function tests for any printing character except for space (` ') or a character for which isalnum(3) is true. The value of the argument must be representable as an unsigned char or the value of EOF. In the ASCII character set, this includes the following characters (with their numeric values shown in octal): 041 ``!'' 042 ``"'' 043 ``#'' 044 ``$'' 045 ``%'' 046 ``&'' 047 ``''' 050 ``('' 051 ``)'' 052 ``*'' 053 ``+'' 054 ``,'' 055 ``-'' 056 ``.'' 057 ``/'' 072 ``:'' 073 ``;'' 074 ``<'' 075 ``='' 076 ``>'' 077 ``?'' 100 ``@'' 133 ``['' 134 ``\'' 135 ``]'' 136 ``^'' 137 ``_'' 140 ```'' 173 ``{'' 174 ``|'' 175 ``}'' 176 ``~''
に、辿り付くという、ダメっぷり。全貌を見るなら、 man ctype か。
gauche流に調べるには?
(define (test c) (char-set-contains? #[[:punct:]] c) (char-set-contains? #[[:cntrl:]] c) (char-set-contains? #[[:blank:]] c) (char-set-contains? #[[:space:]] c) (char-set-contains? #[[:print:]] c) (char-set-contains? #[[:alpha:]] c) (char-set-contains? #[[:lower:]] c) (char-set-contains? #[[:upper:]] c) (char-set-contains? #[[:digit:]] c) (char-set-contains? #[[:xdigit:]] c))
こんな風にしておいて
gosh> (disasm test) main_code (name=test, code=0pb46f00, size=59, const=20, stack=11): args: #f 0 PRE-CALL(2) 6 2 CONST-PUSH #[!-/:-@\[-`{-~] 4 LREF0-PUSH-GREF-CALL(2) #<identifier user#char-set-contains?>; (char-set-contains? #[!-/:-@\[-`{-~] c) 6 PRE-CALL(2) 12 8 CONST-PUSH #[\x00-\x1f\x7f] 10 LREF0-PUSH-GREF-CALL(2) #<identifier user#char-set-contains?>; (char-set-contains? #[\x00-\x1f\x7f] c) 12 PRE-CALL(2) 18 14 CONST-PUSH #[\x09 ] 16 LREF0-PUSH-GREF-CALL(2) #<identifier user#char-set-contains?>; (char-set-contains? #[\x09 ] c) 18 PRE-CALL(2) 24 20 CONST-PUSH #[\x09-\x0d ] 22 LREF0-PUSH-GREF-CALL(2) #<identifier user#char-set-contains?>; (char-set-contains? #[\x09-\x0d ] c) 24 PRE-CALL(2) 30 26 CONST-PUSH #[ -~] 28 LREF0-PUSH-GREF-CALL(2) #<identifier user#char-set-contains?>; (char-set-contains? #[ -~] c) 30 PRE-CALL(2) 36 32 CONST-PUSH #[A-Za-z] 34 LREF0-PUSH-GREF-CALL(2) #<identifier user#char-set-contains?>; (char-set-contains? #[A-Za-z] c) 36 PRE-CALL(2) 42 38 CONST-PUSH #[a-z] 40 LREF0-PUSH-GREF-CALL(2) #<identifier user#char-set-contains?>; (char-set-contains? #[a-z] c) 42 PRE-CALL(2) 48 44 CONST-PUSH #[A-Z] 46 LREF0-PUSH-GREF-CALL(2) #<identifier user#char-set-contains?>; (char-set-contains? #[A-Z] c) 48 PRE-CALL(2) 54 50 CONST-PUSH #[0-9] 52 LREF0-PUSH-GREF-CALL(2) #<identifier user#char-set-contains?>; (char-set-contains? #[0-9] c) 54 CONST-PUSH #[0-9A-Fa-f] 56 LREF0-PUSH-GREF-TAIL-CALL(2) #<identifier user#char-set-contains?>; (char-set-contains? #[0-9A-Fa-f] c) 58 RET #<undef> gosh>
こうですかね。おっと、もう一つ大事な集合を忘れてた。[[:graph:]] こいつが無いと Lisp 1.5のatom を表わす pnameは簡単に表現出来なかったかな? これらの規格(集合)って、 誰が決めたんだろう? 密かにLispの香りがするな。