正则表达式查找匹配文件扩展名的文件,除非文件名包含字符串

时间:2017-03-02 17:31:36

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

我在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的文件,结果缓存除了以i18n开头的所有.js文件。

我尝试进行否定查询以排除模式,但由于非捕获组,它不能作为例外工作:

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

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

2 个答案:

答案 0 :(得分:4)

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

  

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

基于此,配置如下:

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;
  }
}

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

答案 1 :(得分:1)

我确信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. 在第一个时期之后没有量词,所以在任何情况下,它都无法正确获取您的完整文件名。 Lookaheads评估而不消费。
    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,它意识到第一个字符不匹配,所以再次开始搜索。它知道搜索要求在我们的示例中,它从行的开头开始,因此它开始寻找下一个换行符。
  5. 值得注意的是,完全为了将来参考,如果你想使用像\/那样的参考点字符,你会使用像\/这样的表达式,否则就会包含斜杠的路径可能会产生意想不到的结果。

    你拥有所有元素,但正如你所说\/(?!i18n-[^\/]*\.js)[^\/]*(?:css|js)$