preg replace () regex для соответствия относительным путям url() в CSS-файлах

я объединяю некоторые CSS-файлы и записываю их в файл в отдельном каталоге. Я пытаюсь заменить relative url() значения для работы с новым местоположением файла, игнорируя любые абсолютные URL-адреса. Вот пример CSS:

#TEST {
    background:url(test.jpg);
    background:url( 'test.jpg' );
    background:url("test.jpg"  );
    background:url(http://example.com/test.jpg);
    background:url('https://example.com/test.jpg');
    background:url("http://example.com/test.jpg");
    background:url( '//example.com/test.jpg' );
    background:url( "//example.com/test.jpg" );
    background:url(//example.com/test.jpg);
}

все, что не начинается с http://, https:// или // надо сделать $path вводят перед ним (только первые 3 должны совпадать).

желаемый результат:

#TEST {
    background:url(/themes/default/css/test.jpg);
    background:url( '/themes/default/css/test.jpg' );
    background:url("/themes/default/css/test.jpg"  );
    background:url(http://example.com/test.jpg);
    background:url('https://example.com/test.jpg');
    background:url("http://example.com/test.jpg");
    background:url( '//example.com/test.jpg' );
    background:url( "//example.com/test.jpg" );
    background:url(//example.com/test.jpg);
}

однако, код соответствует противоположное:

$path = '/themes/default/css/';
$search = '#url(s*(['"]?)((http(s)?:)?//)#';
$replace = "url({$path}";
$css = preg_replace($search, $replace, $css);

Я знаю, что вы можете использовать что-то вроде !^(http) to не сопоставление строк, которые начинаются с http, но все, что я пробовал, потерпело неудачу (me === плохо в регулярном выражении). Я использовал онлайн тестер регулярных выражений чтобы выяснить это, но я действительно застрял.

это может быть не то, что я использую для решения реальной проблемы (убедившись, что пути работают в скомпилированном CSS), но может ли кто-нибудь помочь мне исправить это regex проблема, или есть лучшее решение?

4 ответов


вы почти там - то, что вы ищете для "не совпадающих строк, начиная с", называется "отрицательным взглядом" и выглядит как (?!http).

и url\( не следует \s*['"]?(https?:)?//, вы:

url\((?!\s*['"]?(http(s)?:)?//)

(Я сохранил это (s) группа захвата там, если вы хотели захватить его, но вам не нужны эти скобки (s); s? это то же самое, что (s)? если вы не заботитесь о захвате).

посмотреть его в действии здесь.

Edit:

поскольку вы хотите поместить $ path после кавычки (если есть), я изменил регулярное выражение на:

url\((?!\s*['"]?(?:https?:)?//)\s*(['"])?

т. е. удалены все скобки захвата, о которых я не забочусь, и добавлен \s*(['"])? захватить какую цитату Это.

Я думаю это в codepad здесь, но на всякий случай, вот код:

$path = '/themes/default/css/';
$search = '#url\((?!\s*[\'"]?(?:https?:)?//)\s*([\'"])?#';
$replace = "url({$path}";

этот pregmatch так же хорош, как выбранный ответ, но также поддерживает необработанные данные

'#url\((?!\s*([\'"]?(((?:https?:)?//)|(?:data\:?:))))\s*([\'"])?#'

вот строительные блоки этого длинного регулярного выражения

$absoluteUrl = '((?:https?:)?//)';
$rawData = '(?:data\:?:)';
$relativeUrl = '\s*([\'"]?((' . $absoluteUrl . ')|(' . $rawData . ')))';
$search = '#url\((?!' . $relativeUrl . ')\s*([\'"])?#';
$replace = "url({$path}";
echo preg_replace($search, $replace, $css);

полный пример

http://codepad.org/NDoya4NC


Я получил эту работу со следующим шаблоном (на основе других ответов здесь):

url\s*\(\s*[\'"]?(?!(((?:https?:)?\/\/)|(?:data\:?:)))([^\'"\)]+)[\'"]?\s*\)

PHP для его запуска:

$path = '/themes/default/css/';
$search = '%url\s*\(\s*[\\'"]?(?!(((?:https?:)?\/\/)|(?:data:?:)))([^\\'")]+)[\\'"]?\s*\)%';
$replace = 'url("' . $path  . '/")';
$css = preg_replace($search, $replace, $css);
  • позволяет пробелы вокруг скобок
  • поддерживает отрицательный lookahead для http, https, data,"//"
  • вставляет кавычки вокруг замененного актива

тест доступен здесь:https://regex101.com/r/zT2gM9/1


получил его на работу:

$sBaseUrl = 'http://example.com/';
$sCss = preg_replace_callback(
    '|url\s*\(\s*[\'"]?([^\'"\)]+)[\'"]\s*\)|',
    function($aMatches) use ($sBaseUrl) {
        return 'url("'. $sBaseUrl . trim($aMatches[1]). '")';
    },
    $sCss
);
print $sCss;