Python re 库的正确使用姿式

前提假设:html

  1. 已经充分掌握 PCRE 风格正则表达式
  2. 熟读 re 库文档

Why

正则表达式的强大已不用我赘述,Python 对此的支持也是十分强大,只不过:python

re.search(pattern, string, flags=0)
re.match(pattern, string, flags=0)
......
复制代码

你能很麻利地使用如上所示的一系列模块级别function 吗,若是你每天用 Python 搞正则匹配,相信你必定很熟练。可是若是你须要每次临时翻阅文档才能知道如何使用它,那么就要思考:是否是 API 在某种程度上设计很差了(有的语言的 pattern 极有可能不是放在首位)。linux

通常来讲,API 的接口参数越少越好,最好的就是没有参数,调用者无脑调用,没有任何记忆负担。而 Python 的 re 库,在我看来,应该至少糅合了「命令式」与「OOP」两种风格,并且接口也不「最小化,正交」。正则表达式

使用姿式

正确的姿式应该是:只用 OOP 风格,而且彻底忘记 re 库提供的一系列模块级别的 function (如 re.search, re.match等)。windows

首先是每次都构造出 Regex 对象,而后由 Regex 对象得出 Match 对象,而后在 Regex 对象和 Match 对象上进行一系列操做。好比:bash

# 1. 构造
    REGEX = re.compile($pattern, flags)     flags是re模块的常量

# 2. 获取 MatchObject
    m = regex.search(string)
   
# 3. 后续 MatchObject 的使用
    1. 获取分组  group()    
    2. groups
    3. groupdict()
复制代码

应用举例

好比我在本身构造的 PathUtils 中,就是如此使用的(我很是喜欢各类各样的 Utils ):函数

from __future__ import (absolute_import, unicode_literals)

import re

class PathUtils(object):
    """路径操做的工具函数"""

    _LINUX_ROOT = '/'
    _LINUX_PATH_SPLITOR = '/'

    @classmethod
    def is_two_linux_path_contains(cls, path1, path2):
        """两个Linux路径是否存在互相包含关系"""

        if path1 == cls._LINUX_ROOT or path2 == cls._LINUX_ROOT:
            return True

        path1_split = path1.split(cls._LINUX_PATH_SPLITOR)
        path2_split = path2.split(cls._LINUX_PATH_SPLITOR)

        for item1, item2 in zip(path1_split, path2_split):
            if item1 != item2:
                return False

        return True

    @classmethod
    def is_valid_linux_path(cls, path):
        if not path:
            return False

        LINUX_PATH_REGEX = r'^(/[^/ ]*)+/?$'

        return cls.is_valid_pattern(path, LINUX_PATH_REGEX)

    @classmethod
    def is_valid_windows_path(cls, path):
        if not path:
            return False

        WINDOWS_PATH_REGEX = r'^[a-zA-Z]:\\(((?![<>:"/\\|?*]).)+((?<![ .])\\)?)*$'

        return cls.is_valid_pattern(path, WINDOWS_PATH_REGEX)

    @classmethod
    def is_valid_path(cls, p):
        if not p:
            return False

        return cls.is_valid_linux_path(p) or cls.is_valid_windows_path(p)

    @classmethod
    def is_valid_pattern(cls, value, pattern):
        if not value:
            return False

        REGEX = re.compile(pattern, re.UNICODE)

        m = REGEX.match(value)

        return True if m else False
复制代码

主要的功能函数就是:工具

@classmethod
def is_valid_pattern(cls, value, pattern):
    if not value:
        return False

    REGEX = re.compile(pattern, re.UNICODE)

    m = REGEX.match(value)

    return True if m else False
复制代码

这样一系列流程下来,个人感觉就是,re 库的接口没有须要记忆,也没有须要临时翻阅文档的地方,而且我只用这一种风格(本身熟悉的,效率老是最高的),好比 re.compile确定只须要传一个参数(flags不是必要的),REGEX_OBJ.match/search确定只须要传need_search_string便可。ui

附录

相关文章
相关标签/搜索