How to use re match objects in a list comprehension

后端 未结 5 1889
说谎
说谎 2020-12-12 14:03

I have a function to pick out lumps from a list of strings and return them as another list:

def filterPick(lines,regex):
    result = []
    for l in lines:
         


        
相关标签:
5条回答
  • 2020-12-12 14:17

    Starting Python 3.8, and the introduction of assignment expressions (PEP 572) (:= operator), it's possible to use a local variable within a list comprehension in order to avoid calling multiple times the same expression:

    # items = ["foo", "bar", "baz", "qurx", "bother"]
    [(x, match.group(1)) for x in items if (match := re.compile('(a|r$)').search(x))]
    # [('bar', 'a'), ('baz', 'a'), ('bother', 'r')]
    

    This:

    • Names the evaluation of re.compile('(a|r$)').search(x) as a variable match (which is either None or a Match object)
    • Uses this match named expression in place (either None or a Match) to filter out non matching elements
    • And re-uses match in the mapped value by extracting the first group (match.group(1)).
    0 讨论(0)
  • 2020-12-12 14:28
    [m.group(1) for l in lines for m in [regex.search(l)] if m]
    

    The "trick" is the for m in [regex.search(l)] part -- that's how you "assign" a value that you need to use more than once, within a list comprehension -- add just such a clause, where the object "iterates" over a single-item list containing the one value you want to "assign" to it. Some consider this stylistically dubious, but I find it practical sometimes.

    0 讨论(0)
  • 2020-12-12 14:33
    return [m.group(1) for m in (re.search(regex, l) for l in lines) if m]
    
    0 讨论(0)
  • 2020-12-12 14:34
    >>> "a" in "a visit to the dentist" 
    True 
    >>> "a" not in "a visit to the dentist" 
    False
    

    That also works with a search query you're hunting down in a list

    `P='a', 'b', 'c'

    'b' in P` returns true

    0 讨论(0)
  • 2020-12-12 14:43

    It could be shortened a little

    def filterPick(lines, regex):
        matches = map(re.compile(regex).match, lines)
        return [m.group(1) for m in matches if m]
    

    You could put it all in one line, but that would mean you would have to match every line twice which would be a bit less efficient.

    0 讨论(0)
提交回复
热议问题