簡體   English   中英

Haskell attoparsec:“閱讀失敗:滿足”

[英]Haskell attoparsec: “Failed reading: satisfyWith”

我想將"John","Kate","Ruddiger"等文本解析為字符串列表。

我試着從解析"John",到Name(String的別名)開始,但它已經失敗, Fail "\\"," [","] "Failed reading: satisfyWith"

問題A:為什么會出現此錯誤,如何解決? (我沒有在attoparsec的源代碼中找到滿意的調用)

問題B:如何使解析器在姓氏后不需要逗號?

{-# LANGUAGE OverloadedStrings #-}

import Data.Attoparsec.Char8 as P
import qualified Data.ByteString.Char8 as BS
import Control.Applicative(many)

data Name = Name String deriving Show

readName =  P.takeWhile (/='"')

entryParser :: Parser Name
entryParser = do
    P.char '"'
    name <- readName
    P.char ','
    return $ Name (BS.unpack name)

someEntry :: IO BS.ByteString
someEntry = do
    return $ BS.pack "\"John\","

main :: IO()
main = do
    someEntry >>= print . parse entryParser  

我使用的是GHC 7.6.3和attoparsec-0.11.3.4。

問題A:為什么會出現此錯誤,如何解決? (我沒有在attoparsec的源代碼中找到滿意的調用)

readName =  P.takeWhile (/='"')

只要謂詞為真, takeWhile消耗takeWhile 為此,你讀的名稱后, " 。沒有被消耗掉這是很容易看到,如果我們去掉P.char ','entryParser

entryParser = P.char '"' >> fmap (Name . BS.unpack) readName
$ runhaskell SO.hs
Done "\"," Name "John"

你需要消費"

entryParser :: Parser Name
entryParser = do
    P.char '"'
    name <- readName
    P.char '"' -- <<<<<<<<<<<<<<<<<<<<<<
    P.char ','
    return $ Name (BS.unpack name)

問題B:如何使解析器在姓氏后不需要逗號?

使用sepBy


現在你的問題已經解決了,讓事情變得更容易一些。 不消耗,在所有entryParser ,而不是只取名字:

entryParser = P.char '"' *> fmap ( Name . BS.unpack ) readName <* P.char '"'

如果您不知道(*>)(<*) ,它們都來自Control.Applicative ,它們基本上意味着“丟棄星號側的任何內容”。

現在,為了解析所有逗號分隔的條目,我們使用sepBy entryParser (P.char ',') 但是,這會導致attoparsec返回Partial:

$ runhaskell SO.hs
Partial _

這實際上是attoparsec的一個特點,你必須記住:

Attoparsec支持增量輸入,這意味着您可以為其提供一個字節字符串,該字符串僅表示要解析的預期數據總量的一部分。 如果您的解析器到達輸入片段的末尾並且可能消耗更多輸入,它將暫停解析並返回Partial延續。

如果您確實想使用增量輸入,請使用parsefeed 否則使用parseOnly 您的示例的完整代碼將是類似的

{-# LANGUAGE OverloadedStrings #-}

import Data.Attoparsec.Char8 as P
import qualified Data.ByteString.Char8 as BS
import Control.Applicative(many, (*>), (<*))

data Name = Name String deriving Show

readName =  P.takeWhile (/='"')

entryParser :: Parser Name
entryParser = P.char '"' *> fmap ( Name . BS.unpack ) readName <* P.char '"'

allEntriesParser = sepBy entryParser (P.char ',')

testString = "\"John\",\"Martha\",\"test\""

main = print . parseOnly allEntriesParser $ testString  
$ runhaskell SO.hs
Right [Name "John",Name "Martha",Name "test"]

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM