解析不以attoparsec中的某些字符结尾的标识符

时间:2015-12-04 05:53:52

标签: haskell negative-lookahead attoparsec

我很难写一个attoparsec解析器来解析Uniform Code for Units of Measure调用<ATOM-SYMBOL>的内容。它被定义为某个类中最长的字符序列(该类包括所有数字0-9),它不以数字结尾。

所以给定输入foo27我想要消费并返回foo,对于237bar26我想要消费并返回237bar,我希望19失败而不消耗任何东西。

我无法弄清楚如何构建takeWhile1takeTillscan,但我可能遗漏了一些明显的东西。

更新: 到目前为止,我最好的尝试是我设法排除完全数字的序列

atomSymbol :: Parser Text
atomSymbol = do
               r <- core
               if (P.all (inClass "0-9") . T.unpack $ r)
                 then fail "Expected an atom symbol but all characters were digits."
                 else return r
  where
    core = A.takeWhile1 $ inClass "!#-'*,0-<>-Z\\^-z|~"

我尝试更改它以测试最后一个字符是否为数字而不是它们都是,但它似乎不会一次回溯一个字符。

更新2:

整个文件位于https://github.com/dmcclean/dimensional-attoparsec/blob/master/src/Numeric/Units/Dimensional/Parsing/Attoparsec.hs。这仅针对来自https://github.com/dmcclean/dimensionalprefixes分支。

1 个答案:

答案 0 :(得分:1)

您应该重新解决问题并分别处理数字跨度(0-9)和非数字字符跨度(!#-'*,:-<>-Z\\^-z|~)。然后可以将感兴趣的句法元素描述为

  • 可选的数字范围,后跟
  • 非数字范围,后跟
  • 零或更多{数字范围后跟非数字范围}。
{-# LANGUAGE OverloadedStrings #-}

module Main where

import Control.Applicative ((<|>), many)
import Data.Char (isDigit)

import Data.Attoparsec.Combinator (option)
import Data.Attoparsec.Text (Parser)
import qualified Data.Attoparsec.Text as A
import Data.Text (Text)
import qualified Data.Text as T

atomSymbol :: Parser Text
atomSymbol = f <$> (option "" digitSpan)
               <*> (nonDigitSpan <|> fail errorMsg)
               <*> many (g <$> digitSpan <*> nonDigitSpan)
  where
    nonDigitSpan = A.takeWhile1 $ A.inClass "!#-'*,:-<>-Z\\^-z|~"
    digitSpan    = A.takeWhile1 isDigit
    f x y xss    = T.concat $ x : y : concat xss
    g x y        = [x,y]
    errorMsg     = "Expected an atom symbol but all characters (if any) were digits."

测试

  

[...]给定输入foo27我想要消费并返回foo,对于237bar26我想要消费并返回237bar,我希望19失败而不消耗任何东西。

λ> A.parseOnly atomSymbol "foo26"
Right "foo"

λ> A.parseOnly atomSymbol "237bar26"
Right "237bar"

λ> A.parseOnly atomSymbol "19"
Left "Failed reading: Expected an atom symbol but all characters (if any) were digits."