[英]Reading POT files in Haskell using Attoparsec
我有一組我想要閱讀的POT文件,以便在Haskell中對翻譯進行后處理。 由於POT文件非常大,我想使用attoparsec來獲得良好的性能。
我嘗試使用hgettext ,但我的任務不是閱讀翻譯我的程序而只是解析POT文件。 基本上,我想獲得(comment, msgid, msgstr)
元組的列表
假設要讀取的POT文件存儲在mypot.pot
,您可以使用此代碼直接在runghc
運行。 我已經使用一些Khan Academy PO文件成功測試了這個,但它目前只適用於簡單文件(沒有復數等),但它很容易擴展:
{-# LANGUAGE OverloadedStrings #-}
import Prelude hiding (takeWhile)
import Data.Attoparsec.ByteString
import Data.Attoparsec.ByteString.Char8 hiding (takeWhile, skipWhile)
import qualified Data.Text.Encoding as TE
import Data.Text(Text)
import Data.Word
import Data.ByteString (unsnoc, ByteString)
import qualified Data.ByteString.Char8 as B
import Control.Applicative
import Control.Monad
import Data.Maybe
import Data.Either
import qualified Data.Text as T
data PORecord = PORecord {
poComment :: Text,
poMsgid :: Text,
poMsgstr :: Text
} deriving (Show, Eq)
takeTillEOL :: Parser ByteString
takeTillEOL = takeWhile (not . isEndOfLine)
parseMsgidMsgstrLine :: ByteString -> Parser Text
parseMsgidMsgstrLine key = do
void (string key) <?> "Line key"
skipSpace
char '"' <?> "Opening Qutotation mark"
val <- takeTillEOL
endOfLine <?> "EOL"
return $ TE.decodeUtf8 $ fromMaybe "" $ (fst <$> unsnoc val)
msgidLine = parseMsgidMsgstrLine "msgid"
msgstrLine = parseMsgidMsgstrLine "msgstr"
escapedTextLine :: Parser Text
escapedTextLine = char '"' *> (TE.decodeUtf8 <$> takeTillEOL) <* endOfLine
--escapedTextLine = do
-- char '"'
-- val <- takeTillEOL
-- return $ (traceShow val ())
nameP :: String -> Parser a -> Parser a
nameP str p = p <?> str
commentLine :: Parser Text
commentLine = nameP "comment line" $ do
char '#' <?> "Line start hash"
-- Skip space but not newline
void $ many (char ' ')
txt <- TE.decodeUtf8 <$> takeTillEOL
endOfLine <?> "EOF"
return txt
emptyLine :: Parser ()
emptyLine = skipSpace <* endOfLine
poRecord :: Parser PORecord
poRecord = do
comments <- many1 commentLine <?> "Comments"
msgidPrimary <- msgidLine <?> "msgid"
extraMsgid <- many escapedTextLine <?> "Extra msgid"
msgstrPrimary <- msgstrLine <?> "msgstr"
extraMsgstr <- many escapedTextLine <?> "Extra msgstr"
endOfLine
let comment = T.intercalate "\n" comments
let msgid = T.intercalate "\n" $ msgidPrimary : extraMsgid
let msgstr = T.intercalate "\n" $ msgstrPrimary : extraMsgstr
return $ PORecord comment msgid msgstr
poFile :: Parser [PORecord]
poFile =
--let options = choice [emptyLine *> pure Nothing, ]
many1 poRecord <?> "PO results"
main :: IO ()
main = do
f <- B.readFile "mypot.pot"
print $ parseOnly poFile f
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.