【问题标题】:Parse identifiers that don't end with certain characters in attoparsec解析不以 attoparsec 中某些字符结尾的标识符
【发布时间】:2015-12-04 05:53:52
【问题描述】:

我一直在编写一个 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 分支构建。

【问题讨论】:

  • 这是一个可能对您有所帮助的组合器:notFollowedBy p = p &gt;&gt; fail "not followed by"
  • 请让您的问题自成一体并添加您的导入语句。在这里,有人想知道(尽管有人可能会猜到)合格的导入 APT 对应于什么。
  • 你能拿走整个令牌,把它倒过来,丢掉数字,倒回去看看有没有剩下的吗?

标签: haskell negative-lookahead attoparsec


【解决方案1】:

您应该重新表述问题并分别处理数字范围 (0-9) 和非数字字符范围 (!#-'*,:-&lt;&gt;-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."

【讨论】:

  • 这是一个很好的答案,非常感谢。对于延迟提供反馈,我感到很抱歉,我在办公室完全被淹没了。
  • @DougMcClean 没问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-11-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-18
相关资源
最近更新 更多