如何在Python中将长正则表达式规则拆分为多行

时间:2011-11-04 08:24:46

标签: python regex

这实际上是否可行?我有一些非常长的正则表达式模式规则很难理解,因为它们不能立即适应屏幕。例如:

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)

反斜杠或三重引号不起作用。

EDIT。我结束使用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's not worry about case, because it seems to differ between Doxygen versions

6 个答案:

答案 0 :(得分:37)

您可以通过引用每个细分来拆分正则表达式模式。不需要反斜杠。

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',并且必须将其放在每个细分之前。

请参阅the docs

答案 1 :(得分:21)

来自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
          )
  

请注意,此功能是在语法级别定义的,但是   在编译时实现。必须使用'+'运算符   在运行时连接字符串表达式。另请注意字面意思   连接可以为每个组件使用不同的引用样式   (甚至混合原始字符串和三重引号字符串)。

答案 2 :(得分:6)

就个人而言,我不使用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)

答案 3 :(得分:5)

为了完整起见,这里缺少的答案使用的是re.Xre.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*")

答案 4 :(得分:0)

Python编译器将自动连接相邻的字符串文字。因此,一种方法是将正则表达式分解为多个字符串,每行一个,并让Python编译器重新组合它们。你在字符串之间有什么空格并不重要,所以你可以使用换行符甚至前导空格来有意义地对齐片段。

答案 5 :(得分:0)

使用字符串连接,如在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)