В PHP вы можете сжимать / уменьшать CSS с помощью регулярного выражения (PCRE)?
(Как теоретический в regex. Я уверен, что есть библиотеки, которые делают это хорошо.)
Фоновая записка: потратив часы на ответ на удаленный (наполовину дерьмовый) вопрос , я подумал, что отправлю часть основного вопроса и отвечу на него сам. Надеюсь, все в порядке.
(Хорошо, это может быть не слишком просто, но довольно прямолинейно.)
Этот ответ предполагает, что требования:
{
, }
;
>
, ~
, +
, -
!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
.
Селектор проверяет удаление пробелов до :
(отрицательный просмотр) может замедлить это по сравнению с соответствующими анализаторами. Парсеры уже знают, находятся ли они в селекторе или нет, и не нужно выполнять дополнительные поиски, чтобы проверить это.
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); }
Вы можете найти на ideone.com :
$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);
Вывод:
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}"
Результаты cssminifier.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}
Длина 263 байт. 12 байт дольше, чем выход майнера regex выше.
cssminifier.com имеет некоторые недостатки по сравнению с этим средним переменным regex:
Вывод CSSTidy 1.3 (через codebeautifier.com ) с самым высоким уровнем сжатия:
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;}
Длина 286 байт. 35 байт дольше, чем выходное средство регулятора regex.
CSSTidy не удаляет комментарии или пробелы в некоторых селекторах. Но он минимизирует стенографические свойства. Последнее, вероятно, должно помочь сжать обычный CSS намного больше.
Минимизированный выход из разных миниуров для того же входа, что и в приведенном выше примере. (Остатки остаточной замены заменяются пробелами).
this answern (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} cssminifier.com (263): 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} CSSTidy 1.3 (286): 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), которые должны быть лучше, и давать более короткий результат, чем это средство для повторного использования.
Вот немного измененная версия ответа @ Qtax, которая решает проблемы с calc()
благодаря альтернативному регулярному выражению из библиотеки Minify @ matthiasmullie .
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' ); return preg_replace( $search_patterns, $replace_patterns, $string ); }
Вот компактный источник того, как я это делаю. С компрессией. И вам не нужно заботиться, если вы что-то изменили в источнике.
На самом деле «// комментарии» не разрешены в css.
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 undestand параметр 'U', который делает регулярное выражение неровным.