Подтвердить что ты не робот

Как разделить длинные правила регулярных выражений на несколько строк в Python

Это действительно выполнимо? У меня есть очень длинные правила шаблонов регулярных выражений, которые трудно понять, потому что они не вписываются в экран сразу. Пример:

test = re.compile('(?P<full_path>.+):\d+:\s+warning:\s+Member\s+(?P<member_name>.+)\s+\((?P<member_type>%s)\) of (class|group|namespace)\s+(?P<class_name>.+)\s+is not documented' % (self.__MEMBER_TYPES), re.IGNORECASE)

Обратная косая черта или тройные кавычки не будут работать.

РЕДАКТИРОВАТЬ. Я закончил, используя режим VERBOSE. Вот как выглядит шаблон регулярного выражения:

test = re.compile('''
  (?P<full_path>                                  # Capture a group called full_path
    .+                                            #   It consists of one more characters of any type
  )                                               # Group ends                      
  :                                               # A literal colon
  \d+                                             # One or more numbers (line number)
  :                                               # A literal colon
  \s+warning:\s+parameters\sof\smember\s+         # An almost static string
  (?P<member_name>                                # Capture a group called member_name
    [                                             #   
      ^:                                          #   Match anything but a colon (so finding a colon ends group)
    ]+                                            #   Match one or more characters
   )                                              # Group ends
   (                                              # Start an unnamed group 
     ::                                           #   Two literal colons
     (?P<function_name>                           #   Start another group called function_name
       \w+                                        #     It consists on one or more alphanumeric characters
     )                                            #   End group
   )*                                             # This group is entirely optional and does not apply to C
   \s+are\snot\s\(all\)\sdocumented''',           # And line ends with an almost static string
   re.IGNORECASE|re.VERBOSE)                      # Let not worry about case, because it seems to differ between Doxygen versions
4b9b3361

Ответ 1

Вы можете разделить шаблон регулярного выражения, указав каждый сегмент. Никаких обратных косых черт не требуется.

test = re.compile(('(?P<full_path>.+):\d+:\s+warning:\s+Member'
                   '\s+(?P<member_name>.+)\s+\((?P<member_type>%s)\) '
                   'of (class|group|namespace)\s+(?P<class_name>.+)'
                   '\s+is not documented') % (self.__MEMBER_TYPES), re.IGNORECASE)

Вы также можете использовать флаг необработанной строки 'r', и вам придется поместить его перед каждым сегментом.

Смотрите документы.

Ответ 2

Из http://docs.python.org/reference/lexical_analysis.html#string-literal-concatenation:

Несколько смежных строковых литералов (ограниченных пробелами), возможно использование различных котировочных конвенций, и их значение так же, как и их конкатенация. Таким образом, "привет" "мир" эквивалентен на "helloworld". Эта функция может использоваться для уменьшения количества необходима обратная косая черта, чтобы разделить длинные строки удобно на длинных строк или даже добавлять комментарии к частям строк, например:

re.compile("[A-Za-z_]"       # letter or underscore
           "[A-Za-z0-9_]*"   # letter, digit or underscore
          )

Обратите внимание, что эта функция определена на синтаксическом уровне, но реализованный во время компиляции. Оператор '+ должен использоваться для конкатенировать строковые выражения во время выполнения. Также обратите внимание, что буквальный конкатенация может использовать разные стили цитирования для каждого компонента (даже смешивая исходные строки и тройные кавычки).

Ответ 3

Лично я не использую re.VERBOSE, потому что мне не нравится скрывать пробелы, и я не хочу ставить '\ s' вместо пробелов, когда '\ s' не требуется.
Чем больше символов в шаблоне регулярных выражений являются точными относительно последовательностей символов, которые нужно уловить, тем быстрее действует объект регулярного выражения. Я почти никогда не использую '\ s'

.

Чтобы избежать re.VERBOSE, вы можете сделать так, как уже было сказано:

test = re.compile(
'(?P<full_path>.+)'
':\d+:\s+warning:\s+Member\s+' # comment
'(?P<member_name>.+)'
'\s+\('
'(?P<member_type>%s)' # comment
'\) of '
'(class|group|namespace)'
#      ^^^^^^ underlining something to point out
'\s+'
'(?P<class_name>.+)'
#      vvv overlining something important too
'\s+is not documented'\
% (self.__MEMBER_TYPES),

re.IGNORECASE)

Нажатие строк влево дает много места для написания комментариев.

.

Но этот способ не так хорош, когда шаблон очень длинный, потому что невозможно написать

test = re.compile(
'(?P<full_path>.+)'
':\d+:\s+warning:\s+Member\s+' # comment
'(?P<member_name>.+)'
'\s+\('
'(?P<member_type>%s)' % (self.__MEMBER_TYPES)  # !!!!!! INCORRECT SYNTAX !!!!!!!
'\) of '
'(class|group|namespace)'
#      ^^^^^^ underlining something to point out
'\s+'
'(?P<class_name>.+)'
#      vvv overlining something important too
'\s+is not documented',

re.IGNORECASE)

то в случае, если шаблон очень длинный, количество строк между часть % (self.__MEMBER_TYPES) в конце
и строку '(?P<member_type>%s)', к которой она применяется. может быть большим, и мы теряем легкость в чтении рисунка.

.

Вот почему я люблю использовать кортеж для написания очень длинного шаблона:

pat = ''.join((
'(?P<full_path>.+)',
# you can put a comment here, you see: a very very very long comment
':\d+:\s+warning:\s+Member\s+',
'(?P<member_name>.+)',
'\s+\(',
'(?P<member_type>%s)' % (self.__MEMBER_TYPES), # comment here
'\) of ',
# comment here
'(class|group|namespace)',
#       ^^^^^^ underlining something to point out
'\s+',
'(?P<class_name>.+)',
#      vvv overlining something important too
'\s+is not documented'))

.

Этот способ позволяет определить шаблон как функцию:

def pat(x):

    return ''.join((\
'(?P<full_path>.+)',
# you can put a comment here, you see: a very very very long comment
':\d+:\s+warning:\s+Member\s+',
'(?P<member_name>.+)',
'\s+\(',
'(?P<member_type>%s)' % x , # comment here
'\) of ',
# comment here
'(class|group|namespace)',
#       ^^^^^^ underlining something to point out
'\s+',
'(?P<class_name>.+)',
#      vvv overlining something important too
'\s+is not documented'))

test = re.compile(pat(self.__MEMBER_TYPES), re.IGNORECASE)

Ответ 4

Просто для полноты, отсутствующий ответ здесь использует флаг re.X или re.VERBOSE, на который в конечном итоге указал OP. Помимо сохранения кавычек, этот метод также переносим в других реализациях регулярных выражений, таких как Perl.

С https://docs.python.org/2/library/re.html#re.X:

re.X
re.VERBOSE

Этот флаг позволяет вам писать регулярные выражения, которые выглядят лучше и удобнее для чтения, позволяя визуально разделять логические разделы шаблона и добавлять комментарии. Пробелы в шаблоне игнорируются, за исключением случаев, когда они находятся в классе символов или перед ним стоит обратная косая черта без экранирования. Когда строка содержит знак #, который не находится в классе символов и перед которым не стоит обратный слеш без экранирования, все символы от самого левого такого # до конца строки игнорируются.

Это означает, что два следующих объекта регулярного выражения, которые соответствуют десятичному числу, функционально равны:

a = re.compile(r"""\d +  # the integral part
                   \.    # the decimal point
                   \d *  # some fractional digits""", re.X)

b = re.compile(r"\d+\.\d*")

Ответ 5

Компилятор Python автоматически объединяет смежные строковые литералы. Таким образом, один из способов сделать это - разбить ваше регулярное выражение на несколько строк, по одному на каждую строку, и позволить компилятору Python их рекомбинировать. Неважно, какие пробелы у вас есть между строками, поэтому вы можете иметь разрывы строк и даже ведущие пробелы для значимого выравнивания фрагментов.

Ответ 6

Либо используйте конкатенацию строк, как в ответе naeg, либо используйте re.VERBOSE/re.X, но будьте осторожны, эта опция игнорирует пробелы и комментарии. У вас есть пробелы в вашем регулярном выражении, поэтому они будут игнорироваться, и вам нужно либо сбежать от них, либо использовать \s

Так, например,

test = re.compile("""(?P<full_path>.+):\d+: # some comment
    \s+warning:\s+Member\s+(?P<member_name>.+) #another comment
    \s+\((?P<member_type>%s)\)\ of\ (class|group|namespace)\s+
    (?P<class_name>.+)\s+is\ not\ documented""" % (self.__MEMBER_TYPES), re.IGNORECASE | re.X)