Python 3.7.1 findall() 未按预期运行

Python 3.7.1 findall() not behaving as expected

首先,我知道这不是 Python 的当前版本并且 findall() 的行为已从 3.6 更改。我不相信这些都是我遇到的问题。而且我还没有找到关于 findall() 自 3.7 以来发生变化的任何信息。

我已经使用 sub() 而不是 findall() 设计了一个修复程序,但我很好奇为什么我必须首先这样做。

我有一个函数可以检查模式是否存在。如果找到,则应该验证该模式之前是否已定义。目前看起来像这样(修复和一些调试代码):

    def _verifyargs(i, end, args):
        '''verify text replacement args'''

        def _findallfix(m):
            formals.append( m.group().upper() )
            return '-xxx- '
            
        # put any formal arguments into a more convenient form for checking

        checkargs = args.keys()
        print( f'checkargs: start={i}, end= {end}, args= {checkargs}' )

        # if there aren't any formal arguments we're still checking for
        # their improper use within the definition body

        while i < end:
            i, text = SRC.fetch( i+1 )
            SRC.setmaster( i )
            formals = []
            text = re.sub( SYM.macLabel, _findallfix, text, flags=re.IGNORECASE )
#           formals = re.findall( SYM.macLabel, text, flags=re.IGNORECASE )
            print( f'line= {i}, formals= {formals}' )
            for formal in formals:
#               formal = formal.upper()
                if not formal in checkargs:
                    UM.undefined( formal )

        SRC.setmaster(end)

模式看起来像这样:

SYM.macLabel = '[?][_A-Z]([.]?[_A-Z0-9])*'              # straight text replacement

当运行针对这段测试代码时:

它产生这个输出:

这很好。这就是我想要的。但是如果我注释掉修复:

    def _verifyargs(i, end, args):
        '''verify text replacement args'''

        def _findallfix(m):
            formals.append( m.group().upper() )
            return '-xxx- '
            
        # put any formal arguments into a more convenient form for checking

        checkargs = args.keys()
        print( f'checkargs: start={i}, end= {end}, args= {checkargs}' )

        # if there aren't any formal arguments we're still checking for
        # their improper use within the definition body

        while i < end:
            i, text = SRC.fetch( i+1 )
            SRC.setmaster( i )
#           formals = []
#           text = re.sub( SYM.macLabel, _findallfix, text, flags=re.IGNORECASE )
            formals = re.findall( SYM.macLabel, text, flags=re.IGNORECASE )
            print( f'line= {i}, formals= {formals}' )
            for formal in formals:
                formal = formal.upper()
                if not formal in checkargs:
                    UM.undefined( formal )

        SRC.setmaster(end)

...然后测试产生这个:

所以 findall() 似乎进行了意想不到的匹配,尽管我的理解是 sub() 和 findall() 应该具有完全相同的匹配行为。

也许我在滥用 sub()。在这个例子中,我根本不关心替换的结果(我把它保存在这里只是因为我可能想看看它),只关心它找到了我期望的模式。关于 findall() 的工作方式,我是否忽略了什么?

TL;DR

使用 (?: ... ) 而不是 ( ... ) 因为 re.findall 给你的是捕获组而不是整个匹配项。

详情

这个问题让我有点疑惑,但是我找到了问题所在

documentation for re.findall 说:

The result depends on the number of capturing groups in the pattern. If there are no groups, return a list of strings matching the whole pattern. If there is exactly one group, return a list of strings matching that group. If multiple groups are present, return a list of tuples of strings matching the groups. Non-capturing groups do not affect the form of the result.

因为你有一组括号,所以你有一个 captugin 组,这就是 re.findall 正在 returning。它符合您的预期,只是 return 与您的预期不同。

通过使用 non-capturing 括号,(?: ... ) 你会得到你想要的结果:全部匹配。

即:

SYM.macLabel = '[?][_A-Z](?:[.]?[_A-Z0-9])*'