Как изменить регулярное выражение, чтобы исключить какой-либо текст? - PullRequest
0 голосов
/ 14 февраля 2020

У меня есть регулярное выражение как '@(?:<script type="text/javascript"|<script)(.*)</script>@msU'. Мне нужно изменить это выражение, чтобы исключить <scripts>, который будет содержать пользовательский атрибут no-defer.

Пример: include (<script type="text/javascript"></script>, <script></script>), exclude (<script no-defer type="text/javascript"></script>)

Как я могу изменить свое регулярное выражение?

Ответы [ 3 ]

1 голос
/ 14 февраля 2020

Это будет сделано:

@<script(?!.*?no-defer).*?>.*?</script>@gm

https://regex101.com/r/NWoKj8/1

0 голосов
/ 14 февраля 2020

Вот альтернатива, использующая DOMDocument. Проще использовать и проверять некоторые теги и / или атрибуты для удаления.

<?php

$html = '<html><body>foo</body><script type="text/javascript"></script><script></script><script no-defer type="text/javascript"></script><script src="" no-defer type="text/javascript"></script></html>';
$doc = new DOMDocument();
$doc->loadHTML($html);
$scripts = $doc->getElementsByTagName('script');
for ($i = $scripts->length; --$i >= 0; ) {
    $item = $scripts->item($i);
    foreach($item->attributes as $att) {
        if($att->name == 'no-defer') {
            $item->parentNode->removeChild($item);
        }
    }
}

$newHtml = $doc->saveHtml();

print_r($newHtml);
0 голосов
/ 14 февраля 2020

Я полностью согласен с комментарием @JayBlanchard, в котором упоминается тот факт, что было бы намного безопаснее использовать PHP DOM-парсер. Затем вы можете легко удалить их, если у них нет атрибута no-defer.

Но хорошо ... если вы действительно хотите сделать это с помощью регулярного выражения, я сначала попытался бы найти все <script> теги и захват атрибутов в группе захвата с чем-то вроде этого:

  • Сначала попробуйте найти теги сценария: <\s*script(?<attributes>[^>]*)>.*?<\s*\/\s*script\s*>
  • Проверьте здесь: https://regex101.com/r/dVEMqA/3/

Идея состоит в том, чтобы выполнить работу за 2 прохода. Это можно сделать с помощью функции PHP preg_replace_callback(), которая позволит вам затем выполнить PHP для каждого совпадения, и вы сможете немного безопасно проанализировать атрибуты и посмотреть, есть ли у вас no-defer и решите оставить его вместо того, чтобы вставлять его в массив сценариев, чтобы перейти в конец страницы.

Вы также можете использовать preg_match_all() и l oop поверх результатов, чтобы решить, что делать. Но я бы лично go сначала для решения парсера DOM, а затем для решения preg_replace_callback() с функцией обратного вызова, которая может получить доступ к массиву для хранения удаленных элементов. Это можно сделать с помощью анонимных (замыкающих) функций и функциональности use ($scripts_to_move_down). Смотрите здесь: https://www.php.net/manual/en/functions.anonymous.php

Это может выглядеть примерно так:


$script_tags_to_move = [];

// Find all script tags and store and then remove them if they don't have the
// no-defer attribute.
$html = preg_replace_callback(
    '/<\s*script(?<attributes>[^>]*)>.*?<\s*\/\s*script\s*>/si',
    function ($matches) use (&$script_tags_to_move) {
        // If the attributes contains no-defer (search is not very safe -> to improve).
        if (preg_match('/(^|\s)no-defer(\s|$)/i', $matches['attributes'])) {
            // Keep the script tag in the HTML.
            return $matches[0];
        } else {
            // Store the script tag.
            $script_tags_to_move[] = $matches[0];
            // And remove it from the HTML.
            return '';
        }
    },
    $html
);

// Inject the script tags at the end, before the closing body tag.
$html = preg_replace(
    '~<\s*/\s*body\s*>~is',
    implode("\n", $script_tags_to_move) . '</body>',
    $html
);

Попробуйте здесь: http://sandbox.onlinephpfunctions.com/code/21a938482e883a1d470e61f312764c112c73bb85

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...