原文:http://regexadvice.com/blogs/mash/archive/2008/03/27/Additional-CSS-minifying-regex-patterns.aspx
注意:本文提到的正则表达式都使用了IgnoreCase=true选项。
我观察了YUI Compressor中用于精简CSS的正则表达式,并给出了一些我认为能有助于这一工作的其他正则表达式。
我所看到的代码已经能够通过简单的字符串替换修剪掉“上-右-下-左”值中不必要的零值。但这是通过三个独立的替换操作完成的。如果能用正则表达式处理这种情况,代码将会变得更简单。
(伪代码)
string.Replace(":0 0 0 0;","0;")
string.Replace(":0 0 0;","0;")
string.Replace(":0 0;","0;")
可以变为:
Regex.Replace(input,":("s*0)("s+0){0,3}"s*;",":0;")
够简单了吧。但我想,怎么能就此停滞不前呢?于是我给出了可以处理所有数值的正则表达式:
:"s*(0|(?:(?:"d*".?"d+(?:p(?:[xct])|(?:[cem])m|%|in|ex))))("s+"1){1,3};
(【译注】测试地址:http://regex-lib.net/Regex/Test/?id=d090db4eaf3b41e2b4e75290ad5fe670)
用于进行替换的字符串很简单:“:$1”。
这一步完成后,下面就是处理各个数值并不全为0的情形。
如果您不大了解CSS,这里简单说一下,此处可能出现4个值:
1)如果只指定一个值,则另外三个值也都隐式地指定为相同的值(X = X X X);
2)如果指定了二个值,则第三个值和第一个相等,第四个值和第二个相等(X Y = X Y X Y);
3)如果指定了三个值,则第四个值等于第二个值(X Y Z = X Y Z Y)。
当然,在精简时您肯定希望用更短的语法。下面的正则表达式可以使其变短。所有这些情况使用的替换字符串都和前面一样,是“:$1”。
将4个参数替换为2个(X Y X Y变为X Y)
:"s*((0|(?:(?:"d?".?"d(?:p(?:[xct])|(?:[cem])m|%|in|ex))))"s+(0|(?:(?:"d?".?"d(?:p(?:[xct])|(?:[cem])m|%|in|ex)))))"s+"2"s+"3; (【译注】测试地址:http://regex-lib.net/Regex/Test/?id=e47bbb7741bd438e9fd37cae7a9d4a24)
4个变为3个(X Y Z Y变为X Y Z)或3个变为2个(X Y X变为X Y)
:"s*((?:(?:0|(?:(?:"d?".?"d(?:p(?:[xct])|(?:[cem])m|%|in|ex))))"s+)?(0|(?:(?:"d?".?"d(?:p(?:[xct])|(?:[cem])m|%|in|ex))))"s+(?:0|(?:(?:"d?".?"d(?:p(?:[xct])|(?:[cem])m|%|in|ex)))))"s+"2; (【译注】测试地址:http://regex-lib.net/Regex/Test/?id=6bddaab88e724f68a5808d352cc556ca)
较长的这个正则表达式只不过是重复了其中一个子模式而已。
基于以上这些正则表达式,我提出了类似的模式,用来处理border-style、outline-style、border-color和outline-color。
border-style/outline-style
替换字符串为“$1-style:$2;”。
(outline|border)-style"s*:"s*(none|hidden|d(?:otted|ashed|ouble)|solid|groove|ridge|inset|outset )(?:"s+"2){1,3}; (【译注】测试地址:http://regex-lib.net/Regex/Test/?id=e46542e4f8bb48429a9f5c9b7fdc546b)
(outline|border)-style"s*:"s*((none|hidden|d(?:otted|ashed|ouble)|solid|groove|ridge|inset|outset )"s+(none|hidden|d(?:otted|ashed|ouble)|solid|groove|ridge|inset|outset ))(?:"s+"3)(?:"s+"4); (【译注】测试地址:http://regex-lib.net/Regex/Test/?id=c5e39786b75143588049042aea0dcd41)
(outline|border)-style"s*:"s*((?:(?:none|hidden|d(?:otted|ashed|ouble)|solid|groove|ridge|inset|outset )"s+)?(none|hidden|d(?:otted|ashed|ouble)|solid|groove|ridge|inset|outset )"s+(?:none|hidden|d(?:otted|ashed|ouble)|solid|groove|ridge|inset|outset ))(?:"s+"3); (【译注】测试地址:http://regex-lib.net/Regex/Test/?id=6558eb133f26435cba770aa1c69f91dd)
border-color/outline-color
替换字符串为“$1-color:$2;”。
(outline|border)-color"s*:"s*((?:"#(?:[0-9A-F]{3}){1,2})|"S+)(?:"s+"2){1,3}; (【译注】测试地址:http://regex-lib.net/Regex/Test/?id=05ec5037fcf843609e14c821b7f76034)
(outline|border)-color"s*:"s*(((?:"#(?:[0-9A-F]{3}){1,2})|"S+)"s+((?:"#(?:[0-9A-F]{3}){1,2})|"S+))(?:"s+"3)(?:"s+"4); (【译注】测试地址:http://regex-lib.net/Regex/Test/?id=4a4c4e9dcdf74a97ba3daa113e56a9ca)
(outline|border)-color"s*:"s*((?:(?:(?:"#(?:[0-9A-F]{3}){1,2})|"S+)"s+)?((?:"#(?:[0-9A-F]{3}){1,2})|"S+)"s+(?:(?:"#(?:[0-9A-F]{3}){1,2})|"S+))(?:"s+"3); (【译注】测试地址:http://regex-lib.net/Regex/Test/?id=82fedb7249b041f3a13e5552fc626b47)
我还给出了其他一些用于替换代码的正则表达式,但由于它们都使用了反相匹配,所以移植性会有问题。
这个模式:
"s+((?:[!{};>+()"],])|(?<={[^{}]*):(?=[^}]*})) (【译注】测试地址:http://regex-lib.net/Regex/Test/?id=928254009ef849cfb565022b6489355e)
用于匹配字符前面不必要的空白字符。要小心伪选择器和伪类前面的冒号。替换字符串为“$1”。
这个模式:
(?<!["x22"x27=]"s*)"#([0-9A-F])"1([0-9A-F])"2([0-9A-F])"3 (【译注】测试地址:http://regex-lib.net/Regex/Test/?id=1e210252d62d4cd2a9f0cb9f2513aeb8)
用于精简16进制颜色值,将AABBCC变为ABC。替换字符串为“$1$2$3”。
我还写了一个用于匹配形如“rgb(x,y,z)”的RGB值的正则表达式,其中的x、y、z都在0-255之间。
rgb"s*"x28((?:25[0-5])|(?:2[0-4]"d)|(?:[01]?"d?"d))"s*,"s*((?:25[0-5])|(?:2[0-4]"d)|(?:[01]?"d?"d))"s*,"s*((?:25[0-5])|(?:2[0-4]"d)|(?:[01]?"d?"d))"s*"x29 (【译注】测试地址:http://regex-lib.net/Regex/Test/?id=c616455c751647ff9c1a430f4f0cfb96)
这个模式仅用于匹配现有代码,并将每个数值放到一个组中,以便进行进一步处理。可以使用matchevaluator遍历每一个匹配并完成10进制到16进制的转换。
我自己进行了一些alpha测试,但我写的css根本不能用作测试材料,所以干脆给大家进行beta测试。我并不是很懂CSS hack,因此我不知道这些精简会不会对CSS hack产生负面影响。我还会将这些信息告诉YUI Compressor的维护者,看看他们能不能采纳