I'm currently working on a minification task as post commit hook. I'm using the current version of yui-compressor for CSS-minification.
Bad thing about the current version of yui-compressor: It breaks certain CSS3-rules that need whitespaces to function properly. (calc(10px + 10px))
To fix the issue i wrote a regular expression that should replace every occurence of calc(...) after compression.
my solution so far is the following RegEx:
Match: /calc\((.*?)([\/\+\-\*])(.*?)\)/g
Replace: calc(\1 \2 \3)
I used two online tools to validate my regular expression:
It also works in PHP. But as soon as i use "sed" only the last occurence per line is being replaced:
Compressed CSS: (before replace with regular expression)
.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 after regular expression: (and correct result)
.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 in debian 8 - (loading the same rules from a file):
sed -r "s/calc\((.*?)([\/\+\-\*])(.*?)\)/calc(\1 \2 \3)/g" style.css
prints the following:
.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)}
It doesn't seem to work with sed. Does anyone have a clue what the heck is going on?
Thanks in advance!
You are trying to use PCRE non-greedy repetition .*?
, but sed
supports only POSIX BRE and ERE, which don't define the non-greedy extension.
Instead, you have to modify your regular expression. In your case, you could use [^-+*/]*
for the first captured group (left operand) -- to match everything until the operator, and [^)]*
to match the second operand -- everything until the closing parenthesis. This will produce the output you expect:
sed -E 's/calc\(([^-+*/]*)([-+*/])([^)]*)\)/calc(\1 \2 \3)/g' style.css
# ^^^^^^^^ ^^^^^^ ^^^^^
# left operand op right operand
# all until op all until )
Note the -E
is equivalent to -r
, but is also works in non-GNU sed
. Also, you don't need to escape your operators inside the brackets. In fact, almost nothing has to be escaped inside the brackets -- except the closing bracket if not supplied as the first character, and ^
if supplied as the first character.
The output you were getting is easy to explain when you note the .*?
is treated as a greedy .*
, repeated zero or more times (?
) -- The first .*?
captures everything until the last operator in line, and the second .*?
will capture the last operand, therefore "expanding" only the last calc
expression in each line.