コメントの抽出

下のページのコメント部分を抜き出すというお題が前から気になっていたので、書き直してシンプルにして(劣化?)みた。コアな部分はあまり変わっていないので面白くないかもしれない。
http://ls-al.jp/blog2/category_11/item_498.html

module Main(main) where
import System.Environment
import System.IO
import Char

main = getArgs >>= (\a-> openBinaryFile (a !! 0) ReadMode) >>= hGetContents >>= (return.getSrcComment) >>= (\a->openBinaryFile "./out.txt" WriteMode >>= (\h-> hPutStr h a >> hClose h))

getSrcComment::String->String
getSrcComment src = 
    concat $map trimEmpty $map getResult $ zip (tail $ scanl commentFilterHs (0,0) [(idx,src)| idx <- [0.. (length src) -1]]) src

commentFilterHs (prevFlag, ownFlag) (idx,str) 
              | prevFlag == 1 && c1 == '-' && c2 == '-' && c3 == '}' = (0,0)
              | prevFlag == 0 && c1 == '{' && c2 == '-' && c3 == '-' = (1,1)
              | prevFlag == 2 && c2 == '\n' = (0,1)
              | prevFlag == 0 && c2 == '-' && c3 == '-' = (2,1)
              | prevFlag == 9 && c2 == '"' = (0,0)
              | prevFlag == 0 && c2 == '"' = (9,0)
              | prevFlag == 9 = (9,0)
              | prevFlag == 1 = (1,1)
              | prevFlag == 2 = (2,1)
                                where
                                  c1 = if idx -1 >= 0 then str !! (idx -1) else '\NUL'
                                  c2 = str !! idx
                                  c3 = if idx +1 < length str then str !! (idx +1) else '\NUL'
commentFilterHs (prevFlag, ownFlag) (idx,str) = (0,0)

getResult ((prevFlag, ownFlag), c) 
          | ownFlag == 1 = c
getResult ((prevFlag, ownFlag), c) = chr 0

trimEmpty c |ord c == 0 = ""
trimEmpty c = c:[]

せっかくコメントを抜き出しても日本語が化けてしまうのでバイナリopenにしてみた。
パラメータの文字数3という制限をなくしたので、解析メソッドを拡張することでもっといろんなことができるかもしれない。
さらに手を加えるとするならStateを使って実装するとか。