Как разделить длинные правила регулярных выражений на несколько строк в 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
Ответы
Ответ 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)