#regex #haskell
#регулярное выражение #haskell
Вопрос:
Допустим, у меня есть следующее регулярное выражение для проверки того, что даты имеют формат ‘ГГГГ-ММ-ДД’:
([12]d{3}-(0[1-9]|1[0-2])-(0[1-9]|[12]d|3[01]))
Использование любого количества онлайн-тестеров регулярных выражений. (Мне нравится https://regex101.com /), становится очевидным, что это работает (например: 2055-12-12 выполняет синтаксический анализ правильно, 2055-13-25 не выполняет синтаксический анализ.
Теперь в haskell:
import Text.Regex.TDFA
import Text.Regex.TDFA.Text ()
let dateRegex = "([12]\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01]))" :: Text
let fromDate' = "2055-12-12"
putStrLn((fromDate' =~ dateRegex)::Text)
выдает пустую строку — не удается найти соответствие. Я понятия не имею, почему. Буду признателен за любую помощь.
Комментарии:
1. Это регулярные выражения в стиле perl (в частности
d
), которые не поддерживаются (это написано в документации пакета regex-tdfa). Не уверен, например.{3}
либо. В документах предлагается regex-pcre, или вы можете использовать выражения в стиле posix, например.[[:digit:]]
.2. @moonGoose Пожалуйста, напишите ответ, когда у вас будет время.
Ответ №1:
d
значение цифры является особенностью регулярных выражений в стиле perl. В документах для regex-tdfa указано, что оно реализует posix extended, а не в стиле perl. Поэтому ваш выбор — переписать с использованием символьных классов posix, ie. использование [[:digit:]]
,
dateRegex = "([12][[:digit:]]{3}-(0[1-9]|1[0-2])-(0[1-9]|[12][[:digit:]]|3[01]))"
или вместо этого import "regex-pcre" Text.Regex.PCRE
с вашим оригинальным регулярным выражением.
Ответ №2:
В Haskell обычный совет — анализировать, не проверять.
import Text.Megaparsec
import Text.Megaparsec.Char
import Data.Time.Calendar
import Control.Monad
import Control.Monad.Fail
import Text.Read
import Data.Maybe
import Data.Void
parseDay :: Parsec Void String Day
parseDay = do
y <- maybe (fail "bad year") pure =<< readMaybe <$> replicateM 4 digitChar
chunk "-"
m <- maybe (fail "bad month") pure =<< readMaybe <$> replicateM 2 digitChar
chunk "-"
d <- maybe (fail "bad day") pure =<< readMaybe <$> replicateM 2 digitChar
maybe (fail "not a Gregorian calendar day") pure $ fromGregorianValid y m d
runParser parseDay "" "2020-11-30"
Right 2020-11-30