在PHP中,您可以使用正则表达式(PCRE)压缩/缩小CSS吗?
(作为正则表达式中的理论。我确信那里有很好的库可以做到这一点。)
背景说明:花了好几个小时写下deleted (half crap) question的答案后,我想我会发布一部分基本问题并自己回答。希望没关系。
答案 0 :(得分:45)
(好吧,这可能不是太简单,但非常直接。)
这个答案假定要求是:
{
,}
,;
,,
,>
,~
,{{1 },+
-
!important
周围的空格,但选择器除外(您必须在其前面留一个空格):
$=
/ (
右侧和[
/ )
]
请注意,此处的要求不包括将CSS属性转换为较短版本(例如使用速记属性而不是几个全长属性,删除不需要的引号)。 这是正则表达式无法解决的问题。
通过两次传递更容易解决这个问题:首先删除注释,然后删除其他所有内容。
应该可以在一次传递中完成,但是你必须用一个匹配空格和注释的表达式替换所有;
(在其他一些修改中)。
删除评论的第一个表达式:
\s
替换为(?xs)
# quotes
(
"(?:[^"\\]++|\\.)*+"
| '(?:[^'\\]++|\\.)*+'
)
|
# comments
/\* (?> .*? \*/ )
。
要删除您可以使用的所有其他内容:
$1
替换为(?six)
# quotes
(
"(?:[^"\\]++|\\.)*+"
| '(?:[^'\\]++|\\.)*+'
)
|
# ; before } (and the spaces after it while we're here)
\s*+ ; \s*+ ( } ) \s*+
|
# all spaces around meta chars/operators
\s*+ ( [*$~^|]?+= | [{};,>~+-] | !important\b ) \s*+
|
# spaces right of ( [ :
( [[(:] ) \s++
|
# spaces left of ) ]
\s++ ( [])] )
|
# spaces left (and right) of :
\s++ ( : ) \s*+
# but not in selectors: not followed by a {
(?!
(?>
[^{}"']++
| "(?:[^"\\]++|\\.)*+"
| '(?:[^'\\]++|\\.)*+'
)*+
{
)
|
# spaces at beginning/end of string
^ \s++ | \s++ \z
|
# double spaces to single
(\s)\s+
。
与正确的解析器相比,选择器检查在$1$2$3$4$5$6$7
之前删除空格(负向前瞻)可以减慢此速度。
解析器已经知道它们是否在选择器中,并且不必进行额外的搜索来检查它。
:
可以找到at ideone.com:
function minify_css($str){
# remove comments first (simplifies the other regex)
$re1 = <<<'EOS'
(?sx)
# quotes
(
"(?:[^"\\]++|\\.)*+"
| '(?:[^'\\]++|\\.)*+'
)
|
# comments
/\* (?> .*? \*/ )
EOS;
$re2 = <<<'EOS'
(?six)
# quotes
(
"(?:[^"\\]++|\\.)*+"
| '(?:[^'\\]++|\\.)*+'
)
|
# ; before } (and the spaces after it while we're here)
\s*+ ; \s*+ ( } ) \s*+
|
# all spaces around meta chars/operators
\s*+ ( [*$~^|]?+= | [{};,>~+-] | !important\b ) \s*+
|
# spaces right of ( [ :
( [[(:] ) \s++
|
# spaces left of ) ]
\s++ ( [])] )
|
# spaces left (and right) of :
\s++ ( : ) \s*+
# but not in selectors: not followed by a {
(?!
(?>
[^{}"']++
| "(?:[^"\\]++|\\.)*+"
| '(?:[^'\\]++|\\.)*+'
)*+
{
)
|
# spaces at beginning/end of string
^ \s++ | \s++ \z
|
# double spaces to single
(\s)\s+
EOS;
$str = preg_replace("%$re1%", '$1', $str);
return preg_replace("%$re2%", '$1$2$3$4$5$6$7', $str);
}
输出:
$in = <<<'EOS'
p * i , html
/* remove spaces */
/* " comments have no escapes \*/
body/* keep */ /* space */p,
p [ remove ~= " spaces " ] :nth-child( 3 + 2n ) > b span i , div::after
{
/* comment */
background : url( " /* string */ " ) blue !important ;
content : " escapes \" allowed \\" ;
width: calc( 100% - 3em + 5px ) ;
margin-top : 0;
margin-bottom : 0;
margin-left : 10px;
margin-right : 10px;
}
EOS;
$out = minify_css($in);
echo "input:\n";
var_dump($in);
echo "\n\n";
echo "output:\n";
var_dump($out);
cssminifier.com与上述测试输入相同的结果:
input:
string(435) "
p * i , html
/* remove spaces */
/* " comments have no escapes \*/
body/* keep */ /* space */p,
p [ remove ~= " spaces " ] :nth-child( 3 + 2n ) > b span i , div::after
{
/* comment */
background : url( " /* string */ " ) blue !important ;
content : " escapes \" allowed \\" ;
width: calc( 100% - 3em + 5px ) ;
margin-top : 0;
margin-bottom : 0;
margin-left : 10px;
margin-right : 10px;
}
"
output:
string(251) "p * i,html body p,p [remove~=" spaces "] :nth-child(3+2n)>b span i,div::after{background:url(" /* string */ ") blue!important;content:" escapes \" allowed \\";width:calc(100%-3em+5px);margin-top:0;margin-bottom:0;margin-left:10px;margin-right:10px}"
长度为263字节。比上面的正则表达式缩写器的输出长12个字节。
与此正则表达式缩小器相比,cssminifier.com有一些缺点:
在预设的最高压缩级别输出CSSTidy 1.3(通过codebeautifier.com):
p * i,html /*\*/body/**/p,p [remove ~= " spaces "] :nth-child(3+2n)>b span i,div::after{background:url(" /* string */ ") blue;content:" escapes \" allowed \\";width:calc(100% - 3em+5px);margin-top:0;margin-bottom:0;margin-left:10px;margin-right:10px}
长度286字节。比正则表达式minifier的输出长35个字节。
CSSTidy不会删除某些选择器中的注释或空格。但它确实缩小了速记属性。后者应该可以帮助压缩正常的CSS。
与上例中相同输入的不同缩小器的缩小输出。 (剩余的换行符用空格替换。)
p * i,html /* remove spaces */
/* " comments have no escapes \*/
body/* keep */ /* space */p,p [ remove ~= " spaces " ] :nth-child( 3 + 2n ) > b span i,div::after{background:url(" /* string */ ") blue!important;content:" escapes \" allowed \\";width:calc(100%-3em+5px);margin:0 10px;}
对于普通的CSS CSSTidy可能是最好的,因为它转换为速记属性。
我假设还有其他缩小器(比如YUI压缩器)应该更好,并且比这个正则表达式缩小器的结果更短。
答案 1 :(得分:4)
以下是@Qtax's answer的略微修改版本,通过@matthiasmullie's Minify library的替代正则表达式解决了calc()
的问题。
function minify_css( $string = '' ) {
$comments = <<<'EOS'
(?sx)
# don't change anything inside of quotes
( "(?:[^"\\]++|\\.)*+" | '(?:[^'\\]++|\\.)*+' )
|
# comments
/\* (?> .*? \*/ )
EOS;
$everything_else = <<<'EOS'
(?six)
# don't change anything inside of quotes
( "(?:[^"\\]++|\\.)*+" | '(?:[^'\\]++|\\.)*+' )
|
# spaces before and after ; and }
\s*+ ; \s*+ ( } ) \s*+
|
# all spaces around meta chars/operators (excluding + and -)
\s*+ ( [*$~^|]?+= | [{};,>~] | !important\b ) \s*+
|
# all spaces around + and - (in selectors only!)
\s*([+-])\s*(?=[^}]*{)
|
# spaces right of ( [ :
( [[(:] ) \s++
|
# spaces left of ) ]
\s++ ( [])] )
|
# spaces left (and right) of : (but not in selectors)!
\s+(:)(?![^\}]*\{)
|
# spaces at beginning/end of string
^ \s++ | \s++ \z
|
# double spaces to single
(\s)\s+
EOS;
$search_patterns = array( "%{$comments}%", "%{$everything_else}%" );
$replace_patterns = array( '$1', '$1$2$3$4$5$6$7$8' );
return preg_replace( $search_patterns, $replace_patterns, $string );
}
答案 2 :(得分:0)
这个问题是关于PHP的,但由于这篇帖子在我用Google搜索“缩小css正则表达式”时位于结果的顶部,我在这里发布了Python改编:
#!/usr/bin/env python
# These regexes were adapted from PCRE patterns by Dustin "lots0logs" Falgout,
# Matthias Mullie (https://stackoverflow.com/a/15195752/299196), and Andreas
# "Qtax" Zetterlund (https://stackoverflow.com/a/44350195/299196).
import re
CSS_COMMENT_STRIPPING_REGEX = re.compile(r"""
# Quoted strings
( "(?:[^"\\]+|\\.)*" | '(?:[^'\\]+|\\.)*' )
|
# Comments
/\* ( .*? \*/ )
""",
re.DOTALL | re.VERBOSE
)
CSS_MINIFICATION_REGEX = re.compile(r"""
# Quoted strings
( "(?:[^"\\]+|\\.)*" | '(?:[^'\\]+|\\.)*' )
|
# Spaces before and after ";" and "}"
\s* ; \s* ( } ) \s*
|
# Spaces around meta characters and operators excluding "+" and "-"
\s* ( [*$~^|]?= | [{};,>~] | !important\b ) \s*
|
# Spaces around "+" and "-" in selectors only
\s*([+-])\s*(?=[^}]*{)
|
# Spaces to the right of "(", "[" and ":"
( [[(:] ) \s+
|
# Spaces to the left of ")" and "]"
\s+ ( [])] )
|
# Spaces around ":" outside of selectors
\s+(:)(?![^\}]*\{)
|
# Spaces at the beginning and end of the string
^ \s+ | \s+ \z
|
# Collapse concurrent spaces
(\s)\s+
""",
re.DOTALL | re.IGNORECASE | re.VERBOSE
)
def minify_css(css):
return CSS_MINIFICATION_REGEX.sub(r"\1\2\3\4\5\6\7\8",
CSS_COMMENT_STRIPPING_REGEX.sub(r"\1", css))
可能与PHP + PCRE版本不完全相同。由于Python的正则表达式库不支持PCRE所做的许多构造,因此我不得不修改PCRE模式。我删除的修饰符可以提高性能,并可能加强恶意输入的正则表达式,所以it's probably not a good idea to use this on untrusted input。
答案 3 :(得分:-1)
这是我如何做的紧凑来源。 随着压缩。如果您在源中更改了某些内容,则无需关心。
事实上,在CSS中不允许使用'// comments'。
ob_start('ob_handler');
if(!file_exists('style/style-min.css)
or filemtime('style/style.css') > filemtime('style/style-min.css')){
$css=file_get_contents('style/style.css');
//you need to escape some more charactes if pattern is an external string.
$from=array('@\\s*/\\*.*\\*/\\s*@sU', '/\\s{2,}/');
$to= array('' , ' ');
$css=preg_replace($from,$to,$css);
$css=preg_replace('@\s*([\:;,."\'{}()])\s*@',"$1",$css);
$css=preg_replace('@;}@','}',$css);
header('Content-type: text/css');
echo $css;
file_put_contents('style/style-min.css',$css);
//etag- modified- cache-control- header
}
else{
//exit if not modified?
//etag- modified- cache-control- header
header('Content-type: text/css');
readfile('style/style-min.css');
}
ob_end_flush();
PS在我准备打字之前谁给了我减号? QTax-很短的时间我忘了逃避$ fom数组中的反斜杠。 PSS。只有新版本的PHP不符合'U'参数,这使得正则表达式不合适。