首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用attoparsec递归返回.txt文件中的所有单词

使用attoparsec递归返回.txt文件中的所有单词
EN

Stack Overflow用户
提问于 2018-05-04 04:57:15
回答 2查看 274关注 0票数 1

我对Haskell相当陌生,我刚刚开始学习如何使用attoparsec从.txt文件中解析大量的英文文本。我知道如何在不使用attoparsec的情况下获取.txt文件中的单词数,但我有点被attoparsec所困。当我在下面运行我的代码时,比如说

“你好,世界,我是埃利奥特·安德森\n我是机器人先生。”

我只回来:

世界,我是艾略特·安德森。“我是机器人先生”(散文=“你好”})

这是我目前的代码:

代码语言:javascript
复制
{-# 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有任何建议吗?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-05-04 05:34:45

你已经有了一个很好的开端--你可以解析一个单词。

接下来需要的是一个Parser [Prose],它可以通过将prose解析器与另一个使用“非散文”部分的解析器结合来表达,使用sepBysepBy1,您可以在Data.Attoparsec.Text文档中查找这些部分。

在那里,获得单词计数的最简单方法是简单地获取所获得的[Prose]的长度。

编辑:

下面是一个最小的工作示例。Parser运行程序已被替换为parseOnly,以允许忽略剩余输入,这意味着尾随的非字不会使解析器变得疯狂。

代码语言:javascript
复制
{-# 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完全相同的结果,因为它也打断了.,'上的单词。修改这种行为只是简单的练习。

希望能有所帮助!)

票数 3
EN

Stack Overflow用户

发布于 2018-05-04 12:42:27

你在正确的轨道上!您已经编写了一个解析器(prose),它读取一个单词:many' letter识别一个字母序列。

现在,您已经知道了如何解析单个单词,您的工作是将其放大,以解析由空格分隔的一系列单词。这就是sepBy所做的事情:p `sepBy` q反复运行p解析器,并在q解析器中穿插。

因此,用于一系列单词的解析器如下(我冒昧地将您的prose重命名为word):

代码语言:javascript
复制
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"]

现在,由letterspace组成的letter将死在非字母的非空格字符上,比如'.。我让你自己想办法解决这个问题。(作为提示,您可能需要将many letter更改为many (letter <|> ...),具体取决于您希望它在各种标点符号上的行为。)

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/50167415

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档