2015-02-16 2 views
1

Как часть попытки написать JSON Parser, я работаю над разбором значения JSON String.Написание парсера для строки JSON

Учитывая следующее определение из Haskell профессора Брента Йорги в course:

-- A parser for a value of type a is a function which takes a String 
-- represnting the input to be parsed, and succeeds or fails; if it 
-- succeeds, it returns the parsed value along with the remainder of 
-- the input. 
newtype Parser a = Parser { runParser :: String -> Maybe (a, String) } 

Я бегу в проблему, поскольку, как я понимаю, мой второй анализатор, zeroOrMore notEndOfString, просто потребляет каждый маркер до достижения конец строки.

data JValue = S String | ...

parseStringJValue :: Parser JValue 
parseStringJValue = S <$> ((char '"') *> (zeroOrMore notEndOfString) <* (char '"')) 

notEndOfString :: Parser Char 
notEndOfString = Parser f 
    where 
    f []  = Nothing 
    f (x:xs) = Just (x, xs) 

Используя этот подход аппликативного, пожалуйста, дайте мне намек в сторону изменения мой выше parseStringJValue на самом деле работает.

Примечание. У меня есть слабое представление о том, как его решить с помощью Monads, но я не уверен, если они требуются.

+0

Подсказка: строка в 'notEndOfString' является результатом вашего синтаксического анализа, а не вводом для анализа. – genisage

+0

Работает ли код? –

+0

Вы, вероятно, хотите 'zeroOrMore notEndOfStringOrQuote'. Например, в parsec я бы просто написал 'many (noneOf" \ "") '. – user2407038

ответ

1

notEndOfString сопрягает и потребляя любые символы в тексте включая " до конца, поэтому он не действует жадность потреблять все символы и никогда не руки прочь к char '"' анализатору. Вам нужно сопоставить любые символы внутри котировок, которые не являются котировкой, что означает, что вам нужно отрицание char.

Если у вас есть char то предположительно вы построили его из satisfy, а значит, вы можете также определить notChar:

notChar c = satisfy (/= c) 

(Примечание, кстати, что notEndOfString просто satisfy id). В противном случае вы можете написать его аналогично char.

Затем вы можете определить анализатор для строк путем создания нескольких других полезных комбинаторов:

bracket l r p = l *> p <* r 
quotes = bracket (char '"') (char '"') 

parseStringJValue = S <$> quotes (zeroOrMore (notChar '"')) 

Обратите внимание, что это не будет обрабатывать побегов ("\"") в кавычки.


Edit: Для того, чтобы обеспечить соблюдение инварианта, которое имплицитно выше, было бы неплохо определить

inside l r = bracket (char l) (char r) (zeroOrMore (notChar r)) 

Тогда parseStringJValue = S <$> inside '"' '"'.

Смежные вопросы