[Python] A question about `[^.]*` in a python RE of a lookahead example

Discussão em 'Python' iniciado por Stack, Abril 18, 2025.

  1. Stack

    Stack Membro Participativo

    I am reading an article about Python regular expressions Regular Expression HOWTO, and I feel a bit confused by the example under the topic of lookahead. The example is about to find filenames with some conditions.

    A filename consists of a base name and an extension, separated by a dot .. For example, a filename can be news.rc and news is the base name and rc is the filename's extension. We want to select filenames where the extension is not bat.

    A appropriate RE from the article is .*[.](?!bat$)[^.]*$.

    The author says that "[^.]* makes sure that the pattern works when there are multiple dots in the filename.", which makes me feel confused. I think that [^.] means to match anything but '.' and [^.]* means to do this action over and over again.

    For example, the regex engine applies .*[.](?!bat$)[^.]*$ to 'autoexec.bat.ty'. .* match 'autoexec' and [.] match '.'. Since 'bat.ty' is not 'bat', (?!bat$) won't fail and start to match [^.]*. What I expect is that it will stop at the second '.' of 'autoexec.bat.ty' and obtain match 'autoexec.bat'. However, the match from python is 'autoexec.bat.ty'.

    p = re.compile('.*[.](?!bat$)[^.]*$')
    m = p.match("autoexec.bat.ty")


    m


    <re.Match object; span=(0, 15), match='autoexec.bat.ty'>
    ​

    Suppose we in a simple case that to use RE [^.]* to match 'AB.CD', it will return 'AB'. I don't understand what the difference is between these two situations.

    print(re.match('[^.]*', 'AB.CD'))


    <re.Match object; span=(0, 2), match='AB'>
    ​

    Continue reading...

Compartilhe esta Página