我目前正在做关于Haskell解析的任务,但我正在努力解决一些基础问题。
作业: 我应该创建一个函数,将一个字符串解析为三元组列表。 以便: A,B,C ,E,D
会导致
Triples [("A","B","C"), ("A","E","D")]
输入字符串将包含; \ n作为新Triple的开头的指示。字符串将以点结尾。 三元组的元素可以是字母或数字或组合, 例如abc,a,1,abc121。
因此,
"a,b,c;\n d,e;\n f,g;\n h,i."
会导致:
Triples [("a","b","c"),("a","d","e"),("a","f","g"),("a","h","i")]
parseTriplesD :: Parser Triples
parseTriplesD = parseTriples
>>= \rs -> return (Triples rs)
这个功能非常简单和正确。获取字符串并使用parseTriples创建的三元组列表返回newtype Triples的对象。
parseTriples :: Parser [Triple]
parseTriples = parseTriple
>>= \r -> ((string ";\n" >> parseTriples >>= \rs -> return (r:rs))
P.<|>(return[r]))
这个功能需要一些工作。我的想法是我使用另一个函数创建一个带有树的三元组输入字符串的元素,忽略/ n并在将创建的三元组添加到返回列表时递归调用它。如果这不起作用,因为它只能创建一个Triple,它将返回一个包含Triple的列表。 我不知何故需要创建第一个Triple,然后使用这个三元组的第一个元素作为其他元素的第一个元素。
问题1 如何创建第一个Triple并将Triple的第一个元素用于其他三元组?
parseTriple :: Parser Triple
parseTriple = P.many (letter<|>digit) >>= \a -> P.char ','
>> P.many (letter<|>digit)>>= \b -> P.char ','
>> P.many (letter<|>digit)>>= \c -> return ((a,b,c))
这个功能非常简单,但我不确定它是否正确。 我的想法是它需要字符串的前几个字符,可以是字母或数字,直到逗号&#34;,&#34; ,并将这些字符保存在一个。 重复3次,创建并返回带有三个元素的Triple。
问题2 在逗号之前,如何只使用字符串中的几个字符(字母或数字EDIT:或空格字符)? P.many(字母&lt; |&gt;数字)是否正确?
三元组数据结构:
newtype Triples = Triples [Triple] deriving (Show,Eq)
type Triple = (String, String, String)
进口:
import Test.HUnit (runTestTT,Test(TestLabel,TestList),(~?=))
import qualified Text.Parsec as P (char,runP,noneOf,many,(<|>),eof)
import Text.ParserCombinators.Parsec
import Text.Parsec.String
import Text.Parsec.Char
import Data.Maybe
测试用例
runParsec :: Parser a -> String -> Maybe a
runParsec parser input = case P.runP parser () "" input of
Left _ -> Nothing
Right a -> Just a
-- | Tests the implementations of 'parseScore'.
main :: IO ()
main = do
testresults <- runTestTT tests
print testresults
-- | List of tests for 'parseScore'.
tests :: Test
tests = TestLabel "parseScoreTest" (TestList [
runParsec parseTriplesD "0,1,2;\n2,3." ~?= Just (Triples [("0","1","2"),("0","2","3")]),
runParsec parseTriplesD "a,bcde ,23." ~?= Just (Triples [("a","bcde ","23")]),
runParsec parseTriplesD "a,b,c;\n d,e;\n f,g;\n h,i." ~?= Just (Triples [("a","b","c"),("a","d","e"),("a","f","g"),("a","h","i")]),
runParsec parseTriplesD "a,bcde23." ~?= Nothing,
runParsec parseTriplesD "a,b,c;d,e;f,g;h,i." ~?= Nothing,
runParsec parseTriplesD "a,b,c;\nd;\nf,g;\nh,i." ~?= Nothing
])
答案 0 :(得分:2)
你能做的是:
使用do
表示法会使您的代码更具可读性
您可以使用alphaNum
作为letter <|> digit
的简写。
parseTriplesD :: Parser Triples
parseTriplesD = Triples <$> parseTriples
parseTriples :: Parser [Triple]
parseTriples = do
a <- parseString
char ','
pairs <- parsePair `sepBy1` string ";\n"
char '.'
eof
return (map (\(b, c) -> (a, b, c)) pairs)
parsePair :: Parser (String, String)
parsePair = do
first <- parseString
char ','
second <- parseString
return (first, second)
parseString :: Parser String
parseString = many (char ' ') >> many (alphaNum <|> char ' ')