sed 正则表达式修复 css 缩小

sed regular expression to fix css minification

我目前正在作为 post 提交挂钩处理缩小任务。我正在使用当前版本的 yui-compressor 进行 CSS-minification.

当前版本的 yui-compressor 的缺点: 它打破了某些需要空格才能正常运行的 CSS3 规则。 (计算(10px + 10px))

为了解决这个问题,我写了一个正则表达式,它应该在压缩后替换每次出现的 calc(...)。

我目前的解决方案是以下正则表达式:

匹配:/calc\((.*?)([\/\+\-\*])(.*?)\)/g

替换:calc( )

我使用了两个在线工具来验证我的正则表达式:

https://regex101.com/

https://regexr.com/

它也适用于 PHP。但是一旦我使用 "sed" 只有每行的最后一次出现被替换:

压缩CSS:(在用正则表达式替换之前)

.test{width:calc(1px+1px)}.test2{left:calc(4%+140px)}.test3{width:calc(1px+1px)}

.test{width:calc(1px-1px)}.test2{left:calc(4%-140px)}.test3{width:calc(1px-1px)}

.test{width:calc(1px*1px)}.test2{left:calc(4%*140px)}.test3{width:calc(1px*1px)}

.test{width:calc(1px/1px)}.test2{left:calc(4%/140px)}.test3{width:calc(1px/1px)}

CSS 在正则表达式之后:(和正确的结果)

.test{width:calc(1px + 1px)}.test2{left:calc(4% + 140px)}.test3{width:calc(1px + 1px)}

.test{width:calc(1px - 1px)}.test2{left:calc(4% - 140px)}.test3{width:calc(1px - 1px)}

.test{width:calc(1px * 1px)}.test2{left:calc(4% * 140px)}.test3{width:calc(1px * 1px)}

.test{width:calc(1px / 1px)}.test2{left:calc(4% / 140px)}.test3{width:calc(1px / 1px)}

在 debian 8 中使用 sed -(从文件加载相同的规则):

sed -r "s/calc\((.*?)([\/\+\-\*])(.*?)\)/calc(  )/g" style.css

打印以下内容:

.test{width:calc(1px+1px)}.test2{left:calc(4%+140px)}.test3{width:calc(1px + 1px)}
.test{width:calc(1px-1px)}.test2{left:calc(4%-140px)}.test3{width:calc(1px-1px)}
.test{width:calc(1px*1px)}.test2{left:calc(4%*140px)}.test3{width:calc(1px * 1px)}
.test{width:calc(1px/1px)}.test2{left:calc(4%/140px)}.test3{width:calc(1px / 1px)}

它似乎不适用于 sed。有谁知道到底发生了什么?

提前致谢!

您正在尝试使用 PCRE 非贪婪重复 .*?,但 sed 仅支持 POSIX BRE and ERE,未定义非贪婪扩展。

相反,您必须修改您的正则表达式。在您的情况下,您可以对第一个捕获的组(左操作数)使用 [^-+*/]* - 匹配运算符之前的所有内容,并使用 [^)]* 匹配第二个操作数 - 直到右括号的所有内容。这将产生您期望的输出:

sed -E 's/calc\(([^-+*/]*)([-+*/])([^)]*)\)/calc(  )/g' style.css
#                ^^^^^^^^  ^^^^^^  ^^^^^
#            left operand    op    right operand 
#            all until op          all until )

注意 -E 等同于 -r,但也适用于非 GNU sed。此外,您不需要在括号内转义运算符。事实上,括号内几乎没有任何内容需要转义——除了右括号(如果没有作为第一个字符提供)和 ^(如果作为第一个字符提供)。

当您注意到 .*? 被视为贪婪的 .*,重复零次或多次 (?) 时,您得到的输出很容易解释 - 第一个.*? 捕获行中最后一个运算符之前的所有内容,第二个 .*? 将捕获最后一个操作数,因此 "expanding" 仅捕获每行中的最后一个 calc 表达式。