Регистрозависимые регулярные выражения

Каков наилучший способ использовать регулярные выражения с параметрами (флагами) в Haskell?

я использую

Text.Regex.PCRE

В документации перечислены несколько интересных опций, таких как compCaseless, compUTF8, ... Но я не знаю, как их использовать с (=~)

3 ответа

Решение

Все Text.Regex.* Модули интенсивно используют классы типов, которые предназначены для расширяемости и поведения, подобного "перегрузке", но делают использование менее очевидным из простого просмотра типов.

Теперь вы, вероятно, начали с основного =~ согласовани.

(=~) ::
  ( RegexMaker Regex CompOption ExecOption source
  , RegexContext Regex source1 target )
  => source1 -> source -> target
(=~~) ::
  ( RegexMaker Regex CompOption ExecOption source
  , RegexContext Regex source1 target, Monad m )
  => source1 -> source -> m target

Использовать =~должен существовать экземпляр RegexMaker ... для LHS, и RegexContext ... для RHS и результата.

class RegexOptions regex compOpt execOpt | ...
      | regex -> compOpt execOpt
      , compOpt -> regex execOpt
      , execOpt -> regex compOpt
class RegexOptions regex compOpt execOpt
      => RegexMaker regex compOpt execOpt source
         | regex -> compOpt execOpt
         , compOpt -> regex execOpt
         , execOpt -> regex compOpt
  where
    makeRegex :: source -> regex
    makeRegexOpts :: compOpt -> execOpt -> source -> regex

Допустимый экземпляр всех этих классов (например, regex=Regex, compOpt=CompOption, execOpt=ExecOption, а также source=String) означает, что можно скомпилировать regex с compOpt,execOpt варианты из какой-то формы source, (Также, учитывая некоторые regex типа, там ровно один compOpt,execOpt набор, который идет вместе с ним. Много разных source Типы в порядке, хотя.)

class Extract source
class Extract source
      => RegexLike regex source
class RegexLike regex source
      => RegexContext regex source target
  where
    match :: regex -> source -> target
    matchM :: Monad m => regex -> source -> m target

Допустимый экземпляр всех этих классов (например, regex=Regex, source=String, target=Bool) означает, что можно сопоставить source и regex дать target, (Другое действует targetс учетом этих конкретных regex а также source являются Int, MatchResult String, MatchArray, так далее.)

Положите их вместе, и это довольно очевидно, что =~ а также =~~ просто удобные функции

source1 =~ source
  = match (makeRegex source) source1
source1 =~~ source
  = matchM (makeRegex source) source1

а также что =~ а также =~~ не оставляйте места для передачи различных вариантов makeRegexOpts,

Вы могли бы сделать свой собственный

(=~+) ::
   ( RegexMaker regex compOpt execOpt source
   , RegexContext regex source1 target )
   => source1 -> (source, compOpt, execOpt) -> target
source1 =~+ (source, compOpt, execOpt)
  = match (makeRegexOpts compOpt execOpt source) source1
(=~~+) ::
   ( RegexMaker regex compOpt execOpt source
   , RegexContext regex source1 target, Monad m )
   => source1 -> (source, compOpt, execOpt) -> m target
source1 =~~+ (source, compOpt, execOpt)
  = matchM (makeRegexOpts compOpt execOpt source) source1

который может быть использован как

"string" =~+ ("regex", CompCaseless + compUTF8, execBlank) :: Bool

или перезаписать =~ а также =~~ с методами, которые могут принимать параметры

import Text.Regex.PCRE hiding ((=~), (=~~))

class RegexSourceLike regex source
  where
    makeRegexWith source :: source -> regex
instance RegexMaker regex compOpt execOpt source
         => RegexSourceLike regex source
  where
    makeRegexWith = makeRegex
instance RegexMaker regex compOpt execOpt source
         => RegexSourceLike regex (source, compOpt, execOpt)
  where
    makeRegexWith (source, compOpt, execOpt)
      = makeRegexOpts compOpt execOpt source

source1 =~ source
  = match (makeRegexWith source) source1
source1 =~~ source
  = matchM (makeRegexWith source) source1

или вы могли бы просто использовать match, makeRegexOptsи т. д. непосредственно там, где это необходимо.

Я ничего не знаю о Haskell, но если вы используете библиотеку регулярных выражений на основе PCRE, то вы можете использовать модификаторы режима внутри регулярного выражения. Чтобы сопоставить регистр без учета регистра, вы можете использовать это регулярное выражение в PCRE:

(?i)caseless

Модификатор режима (? I) переопределяет любой параметр чувствительности к регистру или нечувствительности к регистру, который был установлен вне регулярного выражения. Он также работает с операторами, которые не позволяют вам устанавливать какие-либо параметры.

Точно так же (? S) включает "однострочный режим", который приводит к разрыву строки при совпадении точек, (? M) включает "многострочный режим", который делает совпадения ^ и $ при разрыве строки, и (? X) включается свободно -spacing mode (неэкранированные пробелы и разрывы строк вне классов символов незначительны). Вы можете комбинировать буквы. (? ismx) включает все. Дефис отключает опции. (?-i) делает регулярное выражение чувствительным к регистру. (?xi) запускает регулярное выражение, чувствительное к регистру.

Я считаю, что не могу использовать (=~), если вы хотите использовать compOpt Кроме как defaultCompOpt,

Что-то вроде этой работы:

match (makeRegexOpts compCaseless defaultExecOpt  "(Foo)" :: Regex) "foo" :: Bool

Следующие две статьи должны помочь вам:

Real World Haskell, Глава 8. Эффективная обработка файлов, регулярные выражения и сопоставление имен файлов

Учебник по регулярным выражениям на Haskell

Другие вопросы по тегам