Как разобрать строку целых чисел только в некотором диапазоне с помощью Parsec?
Я пытаюсь изучить Parsec, разбирая строку даты формата "YYYYMMDD", например"20161030". И мое решение таково:
date :: Parser (String, String, String)
date = do
year <- replicateM 4 digit
month <- replicateM 2 digit
day <- replicateM 2 digit
return (year, month, day)
Но проблема в том, что "20161356" также является допустимой датой для моего кода.
Как я могу проверить ,что " мм " находится между 1 и 12; и "DD" находится между 1 и 31?
1 ответ:
Вы можете добавить
guard
, Как предложил Томас М. Дюбюиссон:date :: Parser (String, String, String) date = do year <- replicateM 4 digit month <- replicateM 2 digit day <- replicateM 2 digit guard $ read month > 0 && read month <= 12 && read day > 0 && read day <= 31 return (year, month, day)
Однако это приводит к плохому сообщению об ошибке:
λ> parse date "" "20161356" Left (line 1, column 9):unknown parse error
Мы можем исправить это, объединив
guard
с<?>
, чтобы обеспечить лучшее сообщение об ошибке:date :: Parser (String, String, String) date = do year <- replicateM 4 digit month <- replicateM 2 digit guard (read month > 0 && read month <= 12) <?> "valid month (1–12)" day <- replicateM 2 digit guard (read day > 0 && read day <= 31) <?> "valid day (1–31)" return (year, month, day)
При таком подходе вы получите более полезное сообщение об ошибке:
λ> parse date "" "20161356" Left (line 1, column 7): expecting valid month (1–12)
В качестве примечания я думаю, что этоявляется ценным для проверки (или, по крайней мере, проверки здравомыслия) даты в синтаксическом анализаторе-это гарантирует, что проверка даты составляет с остальной частью ваш синтаксический анализатор и код обработки ошибок. Вы не можете забыть проверить дату позже в коде, и ошибка локализуется правильно, что очень полезно, если вы анализируете документы с большим количеством дат.