【问题标题】:Regex to find files matching file extension except if filename contains string正则表达式查找匹配文件扩展名的文件,除非文件名包含字符串
【发布时间】:2017-07-22 13:45:33
【问题描述】:

我为 nginx 中的特定文件启用了缓存,如下所示:

location ~* \.(?:css|js)$ {
access_log off;
add_header Cache-Control "no-transform,public,max-age=31536000,s-max-age=31536000";
expires 1y;
}   

我想在这里做的是排除所有匹配模式 i18n-*.js 的文件,因此,缓存所有 .js 文件,除了以 i18n 开头的文件。

我尝试进行否定查找以排除该模式,但由于非捕获组,它无法正常工作:

location ~* \.(?!i18n-.*\.js)(?:css|js)$ {
        access_log off;
        add_header Cache-Control "no-transform,public,max-age=31536000,s-max-age=31536000";
        expires 1y;
}

这里的智能解决方案是什么?我不是正则表达式专家,所以简短的解释也会有所帮助。

【问题讨论】:

    标签: regex nginx browser-cache regex-lookarounds nginx-location


    【解决方案1】:

    官方文档describes位置树是如何遍历的:

    检查正则表达式,按照它们出现的顺序 配置文件。正则表达式的搜索终止 在第一次匹配时,使用相应的配置。如果不 找到与正则表达式匹配,然后配置 使用之前记住的前缀位置。

    基于此,配置如下:

    location ~* \.(i18n-.*\.js)$ {
      access_log off;
      expires off;
    }
    
    location ~* \.(css|js)$ {
      access_log off;
      expires 1y;
      add_header Cache-Control public;
    }  
    

    注意:正则表达式中的问号是多余的,除非用作变量docs

    命名的正则表达式捕获可以在以后用作变量:

    server {
      server_name   ~^(www\.)?(?<domain>.+)$;
    
      location / {
        root   /sites/$domain;
      }
    }
    

    如果使用?: 语法跳过捕获组,它们需要稍后使用,否则您可以删除以简化位置语法。

    【讨论】:

    • 谢谢,不更彻底地检查文档是一个糟糕的举动。效果很好!
    【解决方案2】:

    我确信 Anatoly 的回答是您问题的完整解决方案。我只是想提供比评论更多的见解。

    你的正则表达式做得很好。一个很好的问题,你的表达非常接近。

    这就是它不起作用的原因

    .               # matches any character except newline
    (?!i18n-.*\.js) # A negative lookahead which actually does what you intended it to do
    (?:css|js)$`    # extension list
    
    1. 在您的每个匹配项中,. 巧合地匹配了此处的文字句点。没有锚或断言,它被允许从这里开始。 (demo)。如果没有量词,所有尝试都会产生不正确的结果。
    2. 第一个句点之后没有量词,因此无论如何,它都无法正确获取您的完整文件名。前瞻评估不消耗。
      1. a(?=1) 将匹配 aa1,但不会匹配 a2
      2. a(?=1)c 将失败 a1c
      3. a(?=1)1ca(?=1)\dca(?=1).c 等将匹配 a1ca1c
    3. 在这种情况下,您的.* 需要之后。因为前瞻看起来超出了到目前为止所捕获的内容。
      1. 在这里暂停并查看第二个 demo 可能会让您对它的工作有所了解。
      2. 如您所见,它在第一行的第一个字符处意识到匹配将失败,因此它会移动到下一个字符。
    4. 没有断言(例如^)或参考点字符(例如\/),这就是在那种情况下发生的情况。添加这样会使你的表达工作。
      1. here 发生了非常相似的事情,它意识到第一个字符不匹配,因此重新开始搜索。在我们的示例中,它知道搜索需要从行首开始,因此它开始查找下一个换行符。

    值得注意的是,完全为了将来的参考,如果你想使用一个参考点字符,比如\/,你应该使用像\/(?!i18n-[^\/]*\.js)[^\/]*(?:css|js)$这样的表达式,否则包含斜杠的路径可能会产生意想不到的结果.

    你拥有所有的元素,但是正如你所说的I'm no regex expert, so a brief explanation would be helpful, too.

    【讨论】:

    • 哇,没想到回复这么详细,谢谢!我会牢记您的观点,并会花几个小时来研究诸如此类的更复杂的正则表达式(即使这个特殊问题更多地与不阅读 nginx 文档有关)。
    • 虽然它不支持很多实现,但regex101基本上是正则表达式游乐场的最佳工具。您可以做很多事情,同时不会造成伤害。 就像我说的,这是一个很好的问题。这个标签的大部分内容是'这是我输入的一行,你猜模式,我如何让每一个外观都像我想要的那样?我什么都没试过`
    • 我知道你的意思。我不打算问一个看似不必要的问题,但似乎没有人问这个特定的问题,所以我试了一下。此外,我想在其中包含所有可能的信息,以确保问题实际上是可以理解的。是的,regex101 确实是一个非常棒的工具!
    猜你喜欢
    • 2016-12-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-02
    • 2019-07-30
    • 2012-06-05
    相关资源
    最近更新 更多