【问题标题】:Determine whether Python object is regex or string确定 Python 对象是正则表达式还是字符串
【发布时间】:2014-12-08 20:05:28
【问题描述】:

思考练习:编写一个接受正则表达式模式字符串以完全匹配的 Python 函数的“最佳”方法是什么:

import re
strings = [...]

def do_search(matcher):
  """
  Returns strings matching matcher, which can be either a string
  (for exact match) or a compiled regular expression object
  (for more complex matches).
  """
  if not is_a_regex_pattern(matcher):
    matcher = re.compile('%s$' % re.escape(matcher))

  for s in strings:
    if matcher.match(s):
      yield s

那么,is_a_regex_pattern() 的实现思路呢?

【问题讨论】:

    标签: python regex


    【解决方案1】:

    您可以通过re._pattern_type 访问_sre.SRE_Pattern 类型:

    if not isinstance(matcher, re._pattern_type):
        matcher = re.compile('%s$' % re.escape(matcher))
    

    下面是一个演示:

    >>> import re
    >>> re._pattern_type
    <class '_sre.SRE_Pattern'>
    >>> isinstance(re.compile('abc'), re._pattern_type)
    True
    >>>
    

    【讨论】:

    【解决方案2】:

    或者,设为quack

    try:
        does_match = matcher.match(s)
    except AttributeError:
        does_match = re.match(matcher.s)
    
    if does_match:
        yield s
    

    换句话说,将matcher 视为已经是已编译的正则表达式。如果中断了,则将其视为需要编译的 string

    这称为Duck Typing。不是每个人agrees 都应该像这样将异常用于例行突发事件。这是ask-permission versus ask-forgiveness 辩论。 Python 比大多数语言更容易被原谅amenable

    【讨论】:

      【解决方案3】:
      1. 不是字符串:

        def is_a_regex_pattern(s):
          return not isinstance(s, basestring)
        
      2. _sre.SRE_Pattern(虽然它不可导入,所以使用粗字符串匹配):

        def is_a_regex_pattern(s):
          return s.__class__.__name__ == 'SRE_Pattern'
        
      3. 您可以重新编译 SRE_Pattern,它似乎评估相同。

        def is_a_regex_pattern(s):
          return s == re.compile(s)
        

      【讨论】:

        【解决方案4】:

        你可以测试一下,如果matcher 有一个方法match

        import re
        
        def do_search(matcher, strings):
            """
            Returns strings matching matcher, which can be either a string
            (for exact match) or a compiled regular expression object
            (for more complex matches).
            """
            if hasattr(matcher, 'match'):
                test = matcher.match
            else:
                test = lambda s: matcher==s
        
            for s in strings:
                if test(s):
                    yield s
        

        您不应使用全局变量,而应使用第二个参数。

        【讨论】:

          【解决方案5】:

          在 Python 3.7 上,re._pattern_type 重命名为 re.Pattern

          https://stackoverflow.com/a/27366172/895245 因此在那个时候中断了,因为re._pattern_type 没有定义。

          虽然re.Pattern 看起来更好,因此有望更稳定,但在文档中根本没有提到它:https://docs.python.org/3/library/re.html#regular-expression-objects,所以也许依赖它不是一个好主意。

          https://stackoverflow.com/a/46779329/895245 确实有些道理。但是有朝一日str 类添加了.match 方法并做了完全不同的事情是什么? :-) 啊,无类型语言的乐趣。

          所以我想我会选择:

          import re
          
          _takes_s_or_re_type = type(re.compile(''))
          def takes_s_or_re(s_or_re):
              if isinstance(s_or_re, _takes_s_or_re_type):
                  return 0
              else:
                  return 1
          
          assert takes_s_or_re(re.compile('a.c')) == 0
          assert takes_s_or_re('a.c') == 1
          

          因为这只能在公共 API 中断时中断。

          在 Python 3.8.0 上测试。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2021-02-23
            • 1970-01-01
            • 1970-01-01
            • 2011-03-19
            • 1970-01-01
            • 1970-01-01
            • 2010-10-05
            • 1970-01-01
            相关资源
            最近更新 更多