我发现学习如何使用 Attoparsec 非常困难,因为该文档实际上只是一个 API 文档,并且基本上没有任何教程(FPComplete 的教程除外)。如果你知道我可以学习 Attoparsec 的其他地方,那就太好了。
我必须解析简单的分子名称,格式如下:NaCl
, CO2
, H2O
, HCN
, H2O2
. 元素
名称是
一个大写字母,可选地后跟一个小写字母(我不考虑符号长度超过 2 个字符的那些元素)。
一个元素后面可以跟一个数字(这将是公式中的下标)。
新版本(感谢 Mark 和 Tarmil 的建议),编译但不解析:
module Chem
where
import Data.Text (Text, pack)
import Control.Applicative ((<*>), (<$>))
import Data.Attoparsec.Text
data Element = Element String Int deriving (Eq, Ord, Show)
type Molecule = [Element]
parseString :: String -> Result Molecule
parseString = parse (many' parseElement) . pack
parseElement :: Parser Element
parseElement = do
el <- (++) <$> pClass "A-Z" <*> option "" (pClass "a-z")
n <- option 1 decimal
return $ Element el n
pClass :: String -> Parser String
pClass cls = (\c -> [c]) <$> satisfy (inClass cls)
任何建议表示赞赏。
编辑:我设法让它运行。基本上,Partial
返回了一个延续,并且为了完成解析,需要为解析器提供一个空的字节串。所以正确的parseString
是:
parseString = flip feed empty . parse (many' parseElement) . pack
empty
在哪里Data.Text.empty
。但是,由于我不需要增量解析,所以有一个有用的函数parseOnly
,它不等待更多输入并返回一个Either
.
考虑到这一点,我重写了这样的代码(现在可以使用):
module Chem
where
import Data.Text (Text, pack)
import Control.Applicative ((<*>), (<$>))
import Data.Attoparsec.Text
data Element = Element String Int deriving (Eq, Ord, Show)
type Molecule = [Element]
parseString :: String -> Either String Molecule
parseString = parseOnly (many' parseElement) . pack
parseElement :: Parser Element
parseElement = do
el <- (++) <$> pClass "A-Z" <*> option "" (pClass "a-z")
n <- option 1 decimal
return $ Element el n
pClass :: String -> Parser String
pClass cls = (\c -> [c]) <$> satisfy (inClass cls)