简体   繁体   中英

sed regular expression to fix css minification

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:

https://regex101.com/

https://regexr.com/

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM