Как удалить пробелы во встроенных стилях? - PullRequest
0 голосов
/ 28 июня 2019

У меня есть скрипт php, который генерирует письмо в формате html.Чтобы оптимизировать размер, чтобы не нарушить ограничение Google в 102 КБ, я пытаюсь выжать из кода как можно больше ненужных символов.

В настоящее время я использую Emogrifier , чтобы встроить CSSа затем TinyMinify для минимизации.

Выходные данные из этого все еще имеют пробелы между свойствами и значениями во встроенных стилях (например, style="color: #ffffff; font-weight: 16px")

Я разработалследующее регулярное выражение для удаления лишних пробелов, но оно также влияет на фактическое содержимое (например, это и то, что становится этим и этим)

$out = preg_replace("/(;|:)\s([a-zA-Z0-9#])/", "$1$2", $newsletter);

Как я могу изменить это регулярное выражение, ограничиваясьвстроенные стили или есть лучший подход?

Ответы [ 2 ]

1 голос
/ 28 июня 2019

Не существует надежных способов не соответствовать полезной нагрузке (style="" может появиться где угодно) и не соответствовать фактическим значениям CSS (как в content: 'a: b'). Кроме того, рассмотрим также

  • сокращение значений: red короче #f00, что короче #ff0000
  • удалить ведущие и конечные фальшивые, такие как пробелы и точки с запятой
  • редизайн вашего HTML: то есть использование <ins> и <strong> может быть значительно короче, чем использование встроенного CSS

Один из подходов состоит в том, чтобы сначала сопоставить все атрибуты HTML встроенного стиля, а затем работать только с их содержимым, но вы должны сами убедиться в том, насколько хорошо это работает:

$out= preg_replace_callback
( '/( style=")([^"]*)("[ >])/'  // Find all appropriate HTML attributes
, function( $aMatch ) {  // Per match
    // Kill any amount of any kind of spaces after colon or semicolon only
    $sInner= preg_replace
    ( '/([;:])\\s*([a-zA-Z0-9#])/'  // Escaping backslash in PHP string context
    , '$1$2'
    , $aMatch[2]  // Second sub match
    );

    // Kill any amount of leading and trailing semicolons and/or spaces
    $sInner= preg_replace
    ( array( '/^\\s*;*\\s*/', '/\\s*;*\\s*$/' )
    , ''
    , $sInner
    );

    return $aMatch[1]. $sInner. $aMatch[3];  // New HTML attribute
  }
, $newsletter
);
0 голосов
/ 01 июля 2019

Вы не предоставили образец ввода для использования, но вы упомянули, что имеете дело с html. Это должно звучать как сигнал тревоги, что использование регулярных выражений в качестве прямого решения не рекомендуется. Когда вы намереваетесь обработать действительный html, вы должны использовать синтаксический анализатор dom для изоляции атрибутов стиля.

Почему бы вам не использовать регулярные выражения для изоляции объявлений встроенного стиля? Проще говоря: Regex является "не подозревающим об этом". Он не знает, когда он находится внутри или снаружи тега (я предоставлю в своей демонстрации придуманный гаечный ключ, чтобы выразить эту уязвимость. Кроме того, используя синтаксический анализатор dom добавит преимущество правильной обработки различных типов цитирования. Хотя регулярное выражение может быть написано для сопоставления / подтверждения сбалансированного цитирования, оно добавляет значительное раздувание (при правильном выполнении) и ухудшает читабельность и удобство обслуживания вашего сценария.

В моей демонстрации я покажу, как можно просто / точно очистить пробелы после двоеточий, точек с запятой и запятых после выделения истинных встроенных объявлений стилей. Я пошел немного дальше (поскольку на этой странице было упомянуто сгущение цветового шестнадцатеричного кода), чтобы показать, как можно использовать регулярное выражение, чтобы уменьшить некоторые шестизначные шестнадцатеричные коды до трех символов.

Код: ( Демо )

$html = <<<HTML
<div style='font-family: "Times New Roman", Georgia, serif; background-color: #ffffff; '>
  <p>Some text 
    <span class="ohyeah" style="font-weight: bold; color: #ff6633 !important; border: solid 1px grey;">
      Monkeywrench: style="padding: 3px;"
    </span>
    &
    <strong style="text-decoration: underline; ">Underlined</strong>
  </p>
  <h1 style="margin: 1px 2px 3px 4px;">Heading</h1>
  <span style="background-image:     url('images/not_a_hexcode_ffffff.png');    ">Text</span>
</div>
HTML;

$dom = new DOMDocument;
libxml_use_internal_errors(true);
$dom->loadHTML($html, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
foreach ($dom->getElementsByTagName('*') as $node) {
    $style = $node->getAttribute('style');
    if ($style) {
        $patterns = ['~[:;,]\K\s+~', '~#\K([\da-f])\1([\da-f])\2([\da-f])\3~i'];
        $replaces = ['', '\1\2\3'];
        $node->setAttribute('style', preg_replace($patterns, $replaces, $style));
    }
}
$html = $dom->saveHtml();
echo $html;

Выход:

<div style='font-family:"Times New Roman",Georgia,serif;background-color:#fff;'>
  <p>Some text 
    <span class="ohyeah" style="font-weight:bold;color:#f63 !important;border:solid 1px grey;">
      Monkeywrench: style="padding: 3px;"
    </span>
    &amp;
    <strong style="text-decoration:underline;">Underlined</strong>
  </p>
  <h1 style="margin:1px 2px 3px 4px;">Heading</h1>
  <span style="background-image:url('images/not_a_hexcode_ffffff.png');">Text</span>
</div>

Приведенный выше фрагмент использует \K в шаблонах, чтобы избежать использования обходных групп и лишних групп захвата.

Я не пишу шаблон, который удаляет пробел до !important, потому что я прочитал некоторые (не очень свежие) посты, в которых некоторые браузеры выражают ошибочное поведение без пробела.

...