私は Haskell の初心者なので、間違っていることは明らかです...
解析しようとして"1:1,2, 2:18, 3:100"
いる[(1,1), (1,2), (2,18), (3,100)]
ときに、先読みに行き詰まりました。
数字が詩の番号であるかどうかを知るには、コロンを先に見る必要があります。これは、代わりに章番号であるためです。
問題は最後の関数verseNr
にあります。コロンが続かない場合は数値を解析して消費する必要がありますrefGroupByChapter
。
この問題を除けば、うまく機能しているようです:)
import Text.ParserCombinators.Parsec
main = do
case (parse refString "(unknown)" "1:1,2, 2:18, 3:100") of
Left e -> do putStr "parse error at "; print e
Right x -> print x -- expecting: [(1,1), (1,2), (2,18), (3,100)]
refString :: GenParser Char st [(Int, Int)]
refString = do
refGroups <- many refGroupByChapter
eof
return $ concat $ map flatten refGroups
where flatten (_, []) = []
flatten (c, v:vs) = (c, v):(flatten (c, vs))
refGroupByChapter :: GenParser Char st (Int, [Int])
refGroupByChapter = do
chapterNum <- many digit
char ':'
verseNums <- verseNrs
return ((read chapterNum :: Int), verseNums)
verseNrs :: GenParser Char st [Int]
verseNrs = do
first <- verseNr
remaining <- remainingVerseNrs
return (first:remaining)
where
remainingVerseNrs = do -- allow for spaces around the commas
(spaces >> oneOf "," >> spaces >> verseNrs) <|> (return [])
verseNr = try $ do
n <- many1 digit
notFollowedBy $ char ':' -- if followed by a ':' it's a chapter number
return (read n :: Int)