2015-12-04 6 views
3

Я застрял, написав парсер attoparsec, чтобы разобрать, что Uniform Code for Units of Measure вызывает <ATOM-SYMBOL>. Он определяется как самая длинная последовательность символов в определенном классе (этот класс включает в себя все цифры 0-9), который не заканчивается цифрой.Имена парсеров, которые не заканчиваются на определенные символы в attoparsec

Поэтому, учитывая вход foo27 Я хочу, чтобы потреблять и вернуть foo для 237bar26 Я хочу, чтобы потреблять и вернуть 237bar для 19 Я хочу потерпеть неудачу, не потребляя ничего.

Я не могу понять, как это сделать из takeWhile1 или takeTill или scan, но я, вероятно, отсутствует что-то очевидное.

Update: Моя лучшая попытка до сих пор было то, что мне удалось исключить последовательности, которые полностью цифры

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|~" 

Я попытался изменить что проверить, если последний символ был цифра вместо если бы все они были, но он, похоже, не возвращает назад одного персонажа за раз.

Update 2:

Весь файл в https://github.com/dmcclean/dimensional-attoparsec/blob/master/src/Numeric/Units/Dimensional/Parsing/Attoparsec.hs. Это связано только с веткой prefixes от https://github.com/dmcclean/dimensional.

+2

Вот комбинатор, который может помочь вам: 'notFollowedBy р = р >> обанкротиться«не следует»' – arrowd

+0

Пожалуйста, ваш вопрос самодостаточным и добавить свои операторы импорта. Здесь остается удивляться (хотя можно догадаться), что соответствуют соответствующим импортам 'A',' P' и 'T'. – Jubobs

+1

Не могли бы вы взять весь токен, отменить его, сбросить цифры, вернуться назад и проверить, осталось ли что-нибудь? – VlatkoB

ответ

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." 
+0

Это очень хороший ответ, спасибо большое. Прошу прощения за задержку в предоставлении отзывов об этом, я был абсолютно завален в офисе. –

+0

@DougMcClean Нет проблем. – Jubobs