Нет такого комбинатора;если бы он был, он был бы в Text.Parsec.Char (где определены все стандартные функции комбинатора синтаксического анализа, которые включают Char
).Вы должны быть в состоянии определить его довольно легко.
Я не думаю, что вы сможете получить те же преимущества в производительности, которые attoparsec делает с его реализацией , однако;он опирается на внутренний тип FastSet
, который работает только с 8-битными символами.Конечно, если вам не нужна поддержка Unicode, это может не быть проблемой, но код для FastSet
подразумевает, что вы получите непредсказуемые результаты, передавая символы больше '\255'
, так что если выЕсли вы хотите повторно использовать решение на основе FastSet
, вам, по крайней мере, придется читать строки, которые вы анализируете, в двоичном режиме .(Вам также нужно будет скопировать реализацию FastSet
в вашу программу, так как она не экспортируется ...)
Если ваши строки диапазона короткие, то простое решение, подобное этому, вероятно, будет довольноfast:
type Range = (Char, Char)
inClass :: String -> Char -> Bool
inClass = inClass' . parseClass
parseClass :: String -> [Range]
parseClass "" = []
parseClass (a:'-':b:xs) = (a, b) : parseClass xs
parseClass (x:xs) = (x, x) : parseClass xs
inClass' :: [Range] -> Char -> Bool
inClass' cls c = any (\(a,b) -> c >= a && c <= b) cls
Вы даже можете попробовать что-то вроде этого, которое должно быть как минимум столь же эффективным, как и в приведенной выше версии (в том числе, когда совершается много вызовов на один inClass s
)и, кроме того, избегайте издержек обхода списка:
inClass :: String -> Char -> Bool
inClass "" = const False
inClass (a:'-':b:xs) = \c -> (c >= a && c <= b) || f c where f = inClass xs
inClass (x:xs) = \c -> c == x || f c where f = inClass xs
(заботясь о том, чтобы убрать рекурсию из лямбды; я не знаю, может ли GHC сделать это сам.)