我对Haskell相当陌生,我刚刚开始学习如何使用attoparsec从.txt文件中解析大量的英文文本。我知道如何在不使用attoparsec的情况下获取.txt文件中的单词数,但我有点被attoparsec所困。当我在下面运行我的代码时,比如说
“你好,世界,我是埃利奥特·安德森\n我是机器人先生。”
我只回来:
世界,我是艾略特·安德森。“我是机器人先生”(散文=“你好”})
这是我目前的代码:
{-# LANGUAGE OverloadedStrings #-}
import Control.Exception (catch, SomeException)
import System.Environment (getArgs)
import Data.Attoparsec.Text
import qualified Data.Text.IO as Txt
import Data.Char
import Control.Applicative ((<*>), (*>), (<$>), (<|>), pure)
{-
This is how I would usually get the length of the list of words in a .txt file normally.
countWords :: String -> Int
countWords input = sum $ map (length.words) (lines input)
-}
data Prose = Prose {
word :: String
} deriving Show
prose :: Parser Prose
prose = do
word <- many' $ letter
return $ Prose word
main :: IO()
main = do
input <- Txt.readFile "small.txt"
print $ parse prose input另外,我如何获得单词的整数计数,稍后呢?此外,对于如何开始使用attoparsec有任何建议吗?
发布于 2018-05-04 05:34:45
你已经有了一个很好的开端--你可以解析一个单词。
接下来需要的是一个Parser [Prose],它可以通过将prose解析器与另一个使用“非散文”部分的解析器结合来表达,使用sepBy或sepBy1,您可以在Data.Attoparsec.Text文档中查找这些部分。
在那里,获得单词计数的最简单方法是简单地获取所获得的[Prose]的长度。
编辑:
下面是一个最小的工作示例。Parser运行程序已被替换为parseOnly,以允许忽略剩余输入,这意味着尾随的非字不会使解析器变得疯狂。
{-# LANGUAGE OverloadedStrings #-}
module Atto where
--import qualified Data.Text.IO as Txt
import Data.Attoparsec.Text
import Control.Applicative ((*>), (<$>), (<|>), pure)
import qualified Data.Text as T
data Prose = Prose {
word :: String
} deriving Show
optional :: Parser a -> Parser ()
optional p = option () (try p *> pure ())
-- Modified to disallow empty words, switched to applicative style
prose :: Parser Prose
prose = Prose <$> many1' letter
separator :: Parser ()
separator = many1 (space <|> satisfy (inClass ",.'")) >> pure ()
wordParser :: String -> [Prose]
wordParser str = case parseOnly wp (T.pack str) of
Left err -> error err
Right x -> x
where
wp = optional separator *> prose `sepBy1` separator
main :: IO ()
main = do
let input = "Hello World, I am Elliot Anderson. \nAnd I'm Mr.Robot.\n"
let words = wordParser input
print words
print $ length words所提供的解析器没有给出与concatMap words . lines完全相同的结果,因为它也打断了.,'上的单词。修改这种行为只是简单的练习。
希望能有所帮助!)
发布于 2018-05-04 12:42:27
你在正确的轨道上!您已经编写了一个解析器(prose),它读取一个单词:many' letter识别一个字母序列。
现在,您已经知道了如何解析单个单词,您的工作是将其放大,以解析由空格分隔的一系列单词。这就是sepBy所做的事情:p `sepBy` q反复运行p解析器,并在q解析器中穿插。
因此,用于一系列单词的解析器如下(我冒昧地将您的prose重命名为word):
word = many letter
phrase = word `sepBy` some space -- "some" runs a parser one-or-more times
ghci> parseOnly phrase "wibble wobble wubble" -- with -XOverloadedStrings
Right ["wibble","wobble","wubble"]现在,由letter和space组成的letter将死在非字母的非空格字符上,比如'和.。我让你自己想办法解决这个问题。(作为提示,您可能需要将many letter更改为many (letter <|> ...),具体取决于您希望它在各种标点符号上的行为。)
https://stackoverflow.com/questions/50167415
复制相似问题