我试图通过解析格式为" YYYYMMDD"的日期字符串来学习Parsec,例如" 20161030"。我的解决方案是:
date :: Parser (String, String, String)
date = do
year <- replicateM 4 digit
month <- replicateM 2 digit
day <- replicateM 2 digit
return (year, month, day)
但问题在于&#34; 20161356&#34;也是我的代码的有效日期。
如何验证&#34; MM&#34;在1到12之间;和&#34; DD&#34;在1到31之间?
答案 0 :(得分:2)
您可以按照Thomas M. DuBuisson的建议添加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)
作为旁注,我认为 对验证(或至少是完整性检查)解析器中的日期很有价值 - 它确保日期验证与解析器的其余部分组成并出错 - 处理代码。您可以忘记在代码中稍后检查日期,并且错误已正确本地化,如果您正在解析包含大量日期的文档,这非常有用。