/ / Regex за премахване на дублирани скриптове от html файл - regex

Regex за премахване на дублирани скриптове от html файл - regex

Да речем, че имате HTML файл с двойкадублиращи се скриптове, което означава множество външни скриптни етикети за един и същ ресурс, като зареждане jquery 3 пъти на страницата. Има ли ефективен редовен израз, който може да премахне дубликатите, но да запази първия. Дубликатите ще бъдат с едно и също точно име на src.

Езикът е PHP и тук е добър пример:

Преди:

<script src="js/jquery.js" type="text/javascript"></script>
some content
<script src="js/jquery.js" type="text/javascript"></script>
more content
<script src="js/jquery.js" type="text/javascript"></script>

След:

<script src="js/jquery.js" type="text/javascript"></script>
some content
more content

Отговори:

2 за отговор № 1

Опровержение:

Мнозина с право ще заявят, че използването на регулярни изрази за разбор на нередовни езици като HTML е опасно. И те са верни. Единственият начин надеждно тези езици се анализират с анализаторспециално предназначени за тази задача. Решението, използващо регулярни изрази, обикновено има много специални случаи на подлежащ текст, което ще доведе до неговото неуспех, което ще доведе до фалшиви положителни резултати и липсващи съвпадения.

Това каза ...

Ако някой настоява да се използват редовни изразиобработване на HTML / XML маркиране и те са наясно с присъщите ограничения, има начини да се изработи решение, което да минимизира тези потенциални капани, и да направи "много добре" работа (в зависимост от специфичните изисквания на въпроса). Въпреки това, за да се справят правилно с много от редките (но валидни и възможни) крайни случаи (напр. Правилно обработване на атрибутите на HTML тагове, които съдържат) <> ъгловите скоби например), правилният regex често може да бъде доста сложен, а не за слаби сърца.

Разбиране на следното решениеизисква доста дълбоко разбиране на езика regex и основната механика на двигателя с regex. Със сигурност съществуват примери за текст за маркиране, който ще го накара да се провали, но следващото решение трябва да свърши доста добра работа за много случаи на типично маркиране.

Тук е тествана PHP функция, която премахва SCRIPT елементи, които имат дубликат SRC стойности на атрибути:

// Strip all SCRIPT elements having duplicate SRC URLs.
function stripDuplicateScripts($text) {
$re = "%
# Match duplicate SCRIPT element having same SRC attribute URL.
(                   # $1: Everything up to duplicate SCRIPT element.
<script           # literal start of script open tag
(?:               # Zero or more attributes before SRC.
s+             # Whitespace required before attribute.
(?!srcb)       # Assert this attribute is not "SRC".
[w-.:]+       # Non-SRC attribute name.
(?:             # Attribute value is optional.
s*=s*       # Value separated by =, optional ws.
(?:           # Group attribute value alternatives.
"[^"]*"     # Either a double quoted value,
| "[^"]*"  # or a single quoted value,
| [w-.:]+   # or an unquoted value.
)             # End group of value alternatives.
)?              # Attribute value is optional.
)*                # Zero or more attributes before SRC.
s+               # Whitespace required before SRC attrib.
src               # Required SRC attribute name.
s*=s*           # Value separated by =, optional ws.
([""])           # $2: Attrib value opening quote.
((?:(?!2).)+)    # $3: SRC attribute value (a URL).
2                # Attrib value closing quote.
(?:               # Zero or more attributes after SRC.
s+             # Whitespace required before attribute.
[w-.:]+       # Attribute name.
(?:             # Attribute value is optional.
s*=s*       # Value separated by =, optional ws.
(?:           # Group attribute value alternatives.
"[^"]*"     # Either a double quoted value,
| "[^"]*"  # or a single quoted value,
| [w-.:]+   # or an unquoted value.
)             # End group of value alternatives.
)?              # Attribute value is optional.
)*                # Zero or more attributes after SRC.
s*               # Optional whitespace before tag close.
>                 # End of SCRIPT open tag.
</scripts*>      # SCRIPT close tag.
.*?               # Stuff up to duplicate script element.
)                   # End $1: Everything up to duplicate SCRIPT.
<script             # literal start of script open tag
(?:                 # Zero or more attributes before SRC.
s+               # Whitespace required before attribute.
(?!srcb)         # Assert this attribute is not "SRC".
[w-.:]+         # Non-SRC attribute name.
(?:               # Attribute value is optional.
s*=s*         # Value separated by =, optional ws.
(?:             # Group attribute value alternatives.
"[^"]*"       # Either a double quoted value,
| "[^"]*"    # or a single quoted value,
| [w-.:]+     # or an unquoted value.
)               # End group of value alternatives.
)?                # Attribute value is optional.
)*                  # Zero or more attributes before SRC.
s+                 # Whitespace required before SRC attrib.
src                 # Required SRC attribute name.
s*=s*             # Value separated by =, optional ws.
([""])             # $4: Attrib value opening quote.
3                  # This script must have duplicate SRC URL.
4                  # Attrib value closing quote.
(?:                 # Zero or more attributes after SRC.
s+               # Whitespace required before attribute.
[w-.:]+         # Attribute name.
(?:               # Attribute value is optional.
s*=s*         # Value separated by =, optional ws.
(?:             # Group attribute value alternatives.
"[^"]*"       # Either a double quoted value,
| "[^"]*"    # or a single quoted value,
| [w-.:]+     # or an unquoted value.
)               # End group of value alternatives.
)?                # Attribute value is optional.
)*                  # Zero or more attributes after SRC.
s*                 # Optional whitespace before tag close.
>                   # End of SCRIPT open tag.
</scripts*>        # SCRIPT close tag.
s*                 # Strip whitespace following duplicate.
%six";
while (preg_match($re, $text)) {
$text = preg_replace($re, "$1", $text);
}
return $text;
}

Функцията по-горе използва един regex, който еприложена рекурсивно, докато не бъдат намерени съвпадения. Въпреки че на пръв поглед regex прилича на чудовище, всъщност той е доста прав (ако сте добре запознат със синтаксиса на regex) и повечето от текста се състои от описателни коментари. Сложността на този regex е необходима, за да се справят с разнообразието от формати атрибут / стойност, разрешено от HTML. Например, SCRIPT таговете могат да имат произволен брой атрибути преди и след SRC атрибут. Най- SRC стойността на атрибута може да бъде единична или двойна. Всички други атрибути могат да имат стойности, които са котирани или не котирани и може да нямат никаква стойност. Цитираните атрибути могат да съдържат <> ъглови скоби.


1 за отговор № 2

Простият отговор на въпроса ви "Има ли ефективен редовен израз, който може да премахне дубликатите, но запази първото място" е: AFAIK, не - няма достатъчно ефективно да се прави регламентиране.

Основният израз (който може да бъде много неефективен, в зависимост от изходния текст) е както следва:

(<scripts+type="text/javascript"s+src="[^"]*">s*</script>)([sS]*?)1

замени с:

$1$2

Това не се отразява много на отклонението на двата тага (което в този случай трябва да са идентични един към друг) от стандартния формуляр:

<script type="text/javascript" src="javascript.js"></script>

Той трябва по същество да съвпадне и да премахне вторияекземпляр на маркер за скрипт - който точно съвпада с предходния таг на скрипта. Ако се нуждаете от по-голяма гъвкавост в точния формат на таг скрипта и знаете само, че името на файла (URL) ще бъде същото, можете да използвате този израз:

(<scripts+type="text/javascript"s+src="([^"]*)"></script>)([sS]*?)<scripts+type="text/javascript"s+src="2"></script>

замествайки с

$1$3

което ще се справи с разликите в празното пространство, но може да бъде още по-малко ефективно (с почти половината), в зависимост от изходния HTML.

Ефективността се влияе от количеството текст между двете копия на маркерите (около три пъти повече обработка на маркер, който не съвпада съвсем, както и с етикетите, които съвпадат)

РЕДАКТИРАНЕ Вярвам, че ще трябва да се изпълнява веднъж за всекидублира (три появявания на скриптов маркер ще изискват две пробези на този заместител, за да се намали до едно събитие), макар че в момента не мога да изпробвам напълно PHP.


0 за отговор № 3

Ако използвате regex за да анализирате html не ви притеснява, нещо просто
може да работи:

$samp = "
<script src="js/jquery.js" type="text/javascript"></script>
<script src="js/jOOPquery.js" type="text/javascript"></script>
some content
<script type="text/javascript" src="js/jOOPquery.js"></script>
<script src="js/jquery.js" type="text/javascript"></script>
more content
<script src="js/jquery.js" type="text/javascript"></script>
<script src="js/jOOPquery.js" type="text/javascript"></script>
";

$regex =
"(?xs)
(<script (?=s)[^>]* (?i:(?<=s)srcs*=s* "s*([^"]*?)s*") [^>]* (?<!/)>s*</scripts*>
.*?
)<script (?=s)[^>]* (?i:(?<=s)srcs*=s* "s*2s*") [^>]* (?<!/)>s*</scripts*>s*
";

while ($samp =~ s/$regex/$1/g) {}


print "$sampn";

изход:

<script src="js/jquery.js" type="text/javascript"></script>
<script src="js/jOOPquery.js" type="text/javascript"></script>
some content
more content