RegEx, чтобы удалить все разметки между тегами <a и</a>, кроме как в [и]

Попытка выяснить регулярное выражение дает мне судороги мозга:)

Я заменяю тысячи отдельных ссылок href с помощью отдельного короткого кода в постсоветском контенте WordPress, используя плагин, который позволяет запускать регулярные выражения для контента.

Вместо того, чтобы пытаться объединить SQL-запрос с RegEx, я делаю это в два этапа: сначала SQL, чтобы найти/заменить каждый отдельный URL-адрес на отдельный короткий код, а второй этап - удалить остальную часть ' href` link.

Вот некоторые примеры того, что у меня есть с первого шага; как вы можете видеть, URL-адрес был заменен коротким кодом [nggallery id=xxx].

<a href="[nggallery id=xx]"><span class="shutterset">
<img class="alignnone size-large wp-image-23067" title="Image Title" 
src="http://example.com/wp-content/uploads/2015/06/image-title.jpg"
alt="" width="685" height="456" /></span></a>

<a href="[nggallery id=xxxxx]">Click here!</a>

<a title="title title" href="[nggallery id=xxx]" target="_blank">Title Link Title Link</a>

Теперь мне нужно удалить все разметки ссылок href - span, img и т.д. между ведущими <a и заканчивающимися </a>, оставив только короткий код [nggallery id=xxx].

У меня есть начало здесь: https://www.regex101.com/r/rL8wP1/2

Но я не знаю, как предотвратить использование [nggallery id=xxx] короткого кода в RegEx.

Обновление 7/09/2015

@nhahtdh ответ, кажется, работает отлично, не слишком жадный и не ест соседние ссылки html. Используйте ( и ) как разделители и $1 в качестве замены плагином regex в WordPress. (Если вы используете BBEdit, вам нужно будет использовать \1)

( <a\s[^>]*"(\[nggallery[^\]]*\])".*?<\/a> )

Обновление 7/02/2015

Спасибо Fab Sa (ниже), его регулярное выражение https://www.regex101.com/r/rL8wP1/4

<a.*(\[nggallery[^\]+]*\]).*?<\/a>

работает в эмуляторе regex101, но при использовании в текстовом редакторе BBEdit или плагине WordPress, который запускает регулярное выражение, его регулярное выражение удаляет короткий код [nggallery id=***]. Так это слишком жадно? Некоторые другие проблемы?

Обновление 7/01/2015:

Я знаю, я знаю, re: RegEx сопоставляет открытые теги, кроме XHTML автономных тегов ВЫ НЕ МОЖЕТЕ ПОВТОРИТЬ HTML С REGEX

Ответы

Ответ 1

Fab Sa regex <a.*(\[nggallery[^\]+]*\]).*?<\/a> копирует все, когда в одной строке есть несколько тегов <a>, из-за неограниченного .* в начале, который будет соответствовать различным тегам <a>.

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

<a\s[^>]*"(\[nggallery[^\]]*\])".*?<\/a>
  ^^^^^^^

Я запустил по крайней мере одну пробел после a, чтобы убедиться, что он не соответствует некоторым другим тегам, а также некоторым дополнительным ограничениям.

В любом случае, вы сами по себе, если обнаружите, что он не работает в каком-то угловом случае. Это вообще плохая идея манипулировать HTML с регулярным выражением.

Ответ 2

Вы можете использовать это регулярное выражение

<a.*(\[nggallery[^\]+]*\]).*?<\/a>

глобально (флаг g). Это регулярное выражение будет соответствовать ссылке и сохранить часть [nggallery ...]. Вы можете заменить все совпадение на $1, чтобы сохранить сохраненную часть [nggallery ...].

Я обновил ваше регулярное выражение в Интернете: https://www.regex101.com/r/rL8wP1/4

PS: В этом решении [nggallery ...] не обязательно должно быть определенное атрибут, например href. Если вы хотите это сделать, вы можете использовать <a.*href\="(\[nggallery[^\]+]*\])".*?<\/a>

Ответ 3

Правда, вы не можете разобрать html с регулярными выражениями, как сделать поведение пуленепробиваемым с минималистическим лексер-парсером? Это даст вам гораздо большую гибкость и контроль над вашим кодом.

<?php

$src = <<<EOF
<a href="[nggallery id=xx]"><span class="shutterset">
<img class="alignnone size-large wp-image-23067" title="Image Title" 
src="http://example.com/wp-content/uploads/2015/06/image-title.jpg"
alt="" width="685" height="456" /></span></a>

<a href="[nggallery id=xxxxx]">Click here!</a>

<a title="title title" href="[nggallery id=xxx]" target="_blank">Title Link Title Link</a>
EOF;

// we "eat up" the source string by opening <a> tags, closing <a> tags or text
$tokens = array();
while ($src){
    // check if $src begins with this pattern <a (any optional prop)[nggallery (any string)] (any optional prop)>
    if (preg_match('/^<a [^>]*(\[nggallery [^\]]+\])[^>]*>/s', $src, $match)){
        // here you can handle data with more flexibility
        // you can grab the id or the [placeholder] via 
        //$match[1] = [nggallery id=xyz]

        // we store the chunk of string and label it as an opening tag
        $tokens[] = array('type' => 'OPENING_A', 'value' => $match[0]);
    }else if (preg_match('/^<\/a>/s', $src, $match)){
        // we store the chunk of string and label it as a closing tag
        $tokens[] = array('type' => 'CLOSING_A', 'value' => $match[0]);
    }else if (preg_match('/^./s', $src, $match)){
        // we store the chunk of string, in this case a character and label it as text
        $tokens[] = array('type' => 'TEXT', 'value' => $match[0]);
    }
    // finally we remove the identified pattern from the source string
    // and continue "eating it up"
    $src = substr($src, strlen($match[0]));
}

// once the source string has been consumed, we get this array
// var_dump($tokens);
// array (size=247)
//   0 => 
//     array (size=2)
//       'type' => string 'OPENING_A' (length=9)
//       'value' => string '<a href="[nggallery id=xx]">' (length=28)
//   1 => 
//     array (size=2)
//       'type' => string 'TEXT' (length=4)
//       'value' => string '<' (length=1)
//   2 => 
//     array (size=2)
//       'type' => string 'TEXT' (length=4)
//       'value' => string 's' (length=1)
//   3 => 
//     array (size=2)
//       'type' => string 'TEXT' (length=4)
//       'value' => string 'p' (length=1)
//       ... ommited for brevity


// now with all the parsed data, we can rebuild the html
// as needed
$html = '';
// we keep a flag to now if we are inside a tag
// marked with ngggallery
$insideNGGalleryTag = false;

foreach ($tokens as $token){
    if ($token['type'] == 'OPENING_A'){
        $insideNGGalleryTag = true;
        $html .= $token['value'];
    }else if ($token['type'] == 'CLOSING_A'){
        $insideNGGalleryTag = false;
        $html .= $token['value'];
    }else{
        // if we are inside a nggallery tag, we will ignore
        // all text inside it. here you could also remove
        // html properties from the tag, move the [nggallery placeholder]
        // inside the <a> or some other behavior you might need
        if (!$insideNGGalleryTag){
            $html .= $token['value'];
        }
    }
}

// finally echo or write to file the
// modified html, in this case it would return
var_dump($html);
// <a href="[nggallery id=xx]"></a>
// <a href="[nggallery id=xxxxx]"></a>
// <a title="title title" href="[nggallery id=xxx]" target="_blank"></a>

Ответ 4

/<a\b[^>]*href\s*=\s*"(\[nggallery id=[^"]+\])".*?<\/a>/i

Это поместит короткий код [nggallery id=XXX] в группу 1, а затем заменит совпадение содержимым группы 1.

ПРИМЕЧАНИЕ: это предполагает достаточно хорошо отформатированный HTML, применяются обычные заявления об отказе.

Ответ 5

Немного поздно, но я думал, что брошу это в микс. (Примечание - предупреждение!! это может быть трудно смотреть..)

изменено: для BBEdit.
Примечание. BBEdit использует механизм PCRE. Конструкции регулярных выражений BBEdit можно найти
здесь: https://gist.github.com/ccstone/5385334

Отформатирован:

 # (?s)(<a(?=\s)(?>(?:(?<=\s)href\s*=\s*"\s*(\[nggallery\s+id\s*=\s*[^"\]>]*?\])"|".*?"|'.*?'|[^>]*?)+>)(?<!/>)(?(2)|(?!))).*?</a\s*>

 (?s)
 (                             # (1 start), Capture open a tag
      <a                            # Open a tag
      (?= \s )
      (?>                           # Atomic
           (?:
                (?<= \s )
                href \s* = \s*                # href attribute
                "
                \s* 
                (                             # (2 start), Capture shortcode value
                     \[nggallery \s+ 
                     id \s* = \s* [^"\]>]*? 
                     \]
                )                             # (2 end)
                "
             |  " .*? "
             |  ' .*? '
             |  [^>]*? 
           )+
           >
      )
      (?<! /> )                     # Not a self contained closure
      (?(2)                         # Only a tags with href attr, shortcode value
        |  (?!)
      )
 )                             # (1 end)
 .*?                           # Stuff inbetween
 </a \s* >                     # Close a tag

Выход:

 **  Grp 0 -  ( pos 0 , len 240 ) 
<a href="[nggallery id=xx]"><span class="shutterset">
<img class="alignnone size-large wp-image-23067" title="Image Title" 
src="http://example.com/wp-content/uploads/2015/06/image-title.jpg"
alt="" width="685" height="456" /></span></a>  
 **  Grp 1 -  ( pos 0 , len 28 ) 
<a href="[nggallery id=xx]">  
 **  Grp 2 -  ( pos 9 , len 17 ) 
[nggallery id=xx]  
----------------
 **  Grp 0 -  ( pos 244 , len 46 ) 
<a href="[nggallery id=xxxxx]">Click here!</a>  
 **  Grp 1 -  ( pos 244 , len 31 ) 
<a href="[nggallery id=xxxxx]">  
 **  Grp 2 -  ( pos 253 , len 20 ) 
[nggallery id=xxxxx]  
-----------------
 **  Grp 0 -  ( pos 294 , len 90 ) 
<a title="title title" href="[nggallery id=xxx]" target="_blank">Title Link Title Link</a>  
 **  Grp 1 -  ( pos 294 , len 65 ) 
<a title="title title" href="[nggallery id=xxx]" target="_blank">  
 **  Grp 2 -  ( pos 323 , len 18 ) 
[nggallery id=xxx]  

Ответ 6

Вот регулярное выражение, которое идеально соответствует вашим примерам.

(<a.*?href=")|([^\]]*?<\/a>)

Вместо того чтобы пытаться совместить все выражение сразу, я использовал оператор OR для указания двух отдельных регулярных выражений: один для начала тега a, <a.*?href=" и один для конца тега [^\]]*?<\/a>. Это может работать или не работать в одной операции замены, если нет, разбить на две операции замены, сначала запустить одно для регулярного выражения конечного тега, а затем запустить его для стартового тега. Сообщите мне, есть ли у вас дополнительные примеры, которые нарушают этот ответ.

Ответ 7

Я не знаю, почему вы хотите сделать это с помощью regex, когда это можно сделать с помощью манипуляций JavaScript DOM.

Я покажу вам основной способ, чтобы дать вам идею:

var div = document.createElement('div');
div.innerHTML = yourString;
var a = div.querySelector('a');
document.body.innerHTML = a.attributes[0].nodeValue;

Рабочая скрипта

Также проверьте documentFragment

Ответ 8

Поскольку вы не указали, я предполагаю, что нет вложенных тегов привязки, и вы просто хотите извлечь квадратный квадратный квадратный код, который находится там. Я также предполагаю, что идентификационный формат вашего кода "[nggallery".

Найдите с помощью этого

<\s*a(?=\s|>)[^>]*?(\[nggallery[^\]]+\])[^>]*>(.|\n)+?(<\s*\/\s*a\s*>)

ЗАМЕНИТЬ, используя

\1

(который должен быть первым записанным групповым обозначением для BBEdit)

Ответ 9

Как это?

(?<=nggallery\sid=xx]">).*(?=<\/a>)

Используйте глобальные и однострочные модификаторы (-g и -s). Это соответствует всем значениям между <a href="[nggallery id=xx]"> и </a>. Я не уверен, правильно ли я понял вашу проблему или нет... но этот RegEx делает то, что я только что описал.