Ссылка на вложенные группы в JavaScript с использованием замены строки с использованием регулярного выражения

Из-за того, как jQuery работает с тегами script, я счел необходимым выполнить некоторые манипуляции с HTML с использованием регулярных выражений (да, я знаю... не идеальный инструмент для работы). К сожалению, кажется, что мое понимание того, как захваченные группы работают в JavaScript, ошибочно, потому что, когда я пытаюсь это сделать:

var scriptTagFormat = /<script .*?(src="(.*?)")?.*?>(.*?)<\/script>/ig;

html = html.replace(
    scriptTagFormat, 
    '<span class="script-placeholder" style="display:none;" title="$2">$3</span>');

Теги сценария заменяются промежутками, но результирующий атрибут title остается пустым. Разве $2 не должно совпадать с содержимым атрибута src тега скрипта?


person Jacob    schedule 05.05.2011    source источник


Ответы (5)


Вложенность групп не имеет значения; их нумерация строго определяется положением их открывающих скобок в регулярном выражении. В вашем случае это означает, что группа №1 захватывает всю последовательность src="value", а группа №2 захватывает только часть value.

person Alan Moore    schedule 05.05.2011

Попробуй это:

/<script (?:(?!src).)*(?:src="(.*?)")?.*?>(.*?)<\/script>/ig

См. здесь: rubular

Как писала стема, .*? слишком много совпадает. С отрицательным просмотром вперед (?:(?!src).)* вы будете соответствовать только до атрибута src.

Но на самом деле в этом случае вы также можете просто переместить .*? в необязательную часть:

/<script (?:.*?src="(.*?)")?.*?>(.*?)<\/script>/ig

См. здесь: rubular

person morja    schedule 05.05.2011

.*? совпадает слишком много, потому что следующая группа является необязательной, ==> ваш src совпадает с одним из .*? вокруг. если вы удалите ? после вашей первой группы, это сработает.

Обновление: как указал @morja, ваше решение состоит в том, чтобы переместить первый .*? в необязательную часть src.

Просто для полноты: /<script (?:.*?(src="(.*?)"))?.*?>(.*?)<\/script>/ig

Вы можете увидеть это здесь, на rubular (также исправлена ​​моя ссылка)

Если вы не хотите использовать содержимое первой группы захвата, сделайте ее группой без захвата, используя (?:)

/<script (?:.*?(?:src="(.*?)"))?.*?>(.*?)<\/script>/ig

Тогда ваш желаемый результат будет в $1 и $2.

person stema    schedule 05.05.2011
comment
Я просто хочу захватить атрибут src тега script, если он существует, независимо от того, где он находится в теге. - person Jacob; 06.05.2011

Не могли бы вы опубликовать html, который вы получаете? Ваш код отлично работает в простом примере: jsfiddle (предупреждение: окно предупреждения)

Мое первое предположение заключается в том, что один из ваших тегов сценария не имеет src, что означает, что у вас осталась одна группа захвата (содержимое сценария).

person WSkid    schedule 05.05.2011
comment
Интересно... если вы поставите type="text/javascript" перед атрибутом src, вы увидите проблему. Похоже, проблема может быть не в группах, а в том, как работает нежадный захват. - person Jacob; 06.05.2011

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

var scriptTagFormat = /<script\s+((.*?)="(.*?)")*\s*>(.*?)<\/script>/ig;

html = html.replace(
    scriptTagFormat, 
    '<span class="script-placeholder" style="display:none;" $1>$4</span>');

Раньше я хотел избежать установки нестандартных атрибутов для замены span. Вместо этого этот код слепо копирует все атрибуты. К счастью, нестандартные атрибуты не удаляются из DOM при вставке HTML, так что для моих целей это подойдет.

person Jacob    schedule 05.05.2011