【问题标题】:RegEx to remove all markup between <a and </a> tags except for within [ and ]正则表达式删除 <a 和 </a> 标记之间的所有标记,除了 [ 和 ]
【发布时间】:2015-09-17 18:02:30
【问题描述】:

试图找出正则表达式让我脑筋急转弯 :)

我正在使用允许我在内容上运行正则表达式的插件,用 WordPress 帖子内容中的单个短代码替换数千个单独的 hreflinks。

我没有尝试将 SQL 查询与 RegEx 结合起来,而是分两个阶段进行:首先使用 SQL 查找/替换每个单独的 URL 到单独的短代码,第二阶段,删除其余的 ' href` 链接标记。

这些是我从第一步开始得到的一些例子;如您所见,该 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>

现在,我需要删除前导 &lt;a 和结尾 &lt;/a&gt; 之间的所有 href 链接标记 - spanimg 等,只留下短代码 [nggallery id=xxx]

我从这里开始:https://www.regex101.com/r/rL8wP1/2

但我不知道如何防止 [nggallery id=xxx] 短代码在 RegEx 中被捕获。

2015 年 7 月 9 日更新

@nhahtdh 的答案似乎完美无缺,不太贪婪,并且不吃相邻的 html 链接。使用() 作为分隔符,使用$1 作为WordPress 中正则表达式插件的替代品。 (如果使用BBEdit,则需要使用\1

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

2015 年 7 月 2 日更新

感谢 Fab Sa (在下面回答),他的正则表达式 https://www.regex101.com/r/rL8wP1/4

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

在 regex101 模拟器中工作,但在 BBEdit 文本编辑器或运行 regex 的 WordPress 插件中使用时,他的 regex 会删除 [nggallery id=***] 短代码。所以是不是太贪心了?其他问题?

2015 年 7 月 1 日更新:

我知道,我知道,回复:RegEx match open tags except XHTML self-contained tags 你不能使用正则表达式解析 HTML

【问题讨论】:

  • 你在执行什么正则表达式?我会捕获短代码,然后将其重新插入替换。也许像regex101.com/r/rL8wP1/5 然后$1 这样的东西会有你的简码。如果您希望括号将括号移到括号之外。
  • 你可以this正则表达式然后替换捕获的部分。我认为正则表达式可以改进,但这有效。
  • @vks,谢谢,但这仍然会删除短代码....
  • 试试&lt;a.*?(\[nggallery[^\]]*\]).*?&lt;\/a&gt;
  • @markratledge 你必须替换为$1

标签: html regex html-parsing


【解决方案1】:

这有点晚了,但我想我会把它混在一起。
(注意-警告!!这可能很难看..)

修改:用于 BBEdit。
注意 - BBEdit 使用 PCRE 引擎。可以找到 BBEdit 正则表达式构造
这里:https://gist.github.com/ccstone/5385334

Formatted:

 # (?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]  

【讨论】:

  • @sin,谢谢,这很有趣,而且看起来很不一样。这是一件很难的事情。出于某种原因,这两个正则表达式都会使我的编辑器 BBEdit 崩溃。似乎创建了一个循环,并且 BBEdit 在警告我正在查找/替换之后冻结了....
  • @markratledge - 确实,这是错误的。更改了 BBEdit 的正则表达式。我认为这个现在有效。无论如何,试试看。
  • @markratledge - 嘿,没问题。正则表达式可能看起来很复杂,但它内置了安全功能,简单的表达式无法解释处理可能的格式错误的 html,但仍然知道正确的结束括号。它是可修改的,而且快如闪电,fwiw。通常,将解析有效标签,然后解析 attr/vals 正则表达式。
【解决方案2】:

的确,您不能使用正则表达式解析 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>

【讨论】:

  • 谢谢,这是个好主意,我一定要试试。我实际上需要更改 WordPress 帖子中的内容,所以我需要运行正则表达式,或者,如果是 php,则使用 ajax 例程来访问 WordPress 数据库而不会超时
【解决方案3】:

由于您没有指定,我假设没有嵌套的锚标记,您只是想提取其中的方括号代码。我还假设您的代码的识别格式是“[nggallery”。

使用这个查找

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

替换
\1

(这应该是 BBEdit 的第一个捕获的组符号)

【讨论】:

    【解决方案4】:

    我不知道您为什么要使用正则表达式来执行此操作,因为它可以使用 JavaScript DOM 操作来完成。

    我会告诉你基本的方法,给你一个想法:

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

    Working Fiddle

    同时检查documentFragment

    【讨论】:

    • 谢谢,这是可能的,但我需要写入数据库并保存更改,因为内容在 WordPress 中。
    【解决方案5】:

    这是一个与您的示例完美匹配的正则表达式。

    (&lt;a.*?href=")|([^\]]*?&lt;\/a&gt;)

    我没有尝试一次匹配整个表达式,而是使用 OR 运算符指定两个单独的正则表达式,一个用于 a 标记的开头,&lt;a.*?href=" 和一个用于 a 标记的结尾 @987654324 @。这可能会或可能不会在单个替换操作中起作用,如果没有,请将其拆分为两个替换操作,首先为结束标签正则表达式运行一个,然后为开始标签运行一个。如果您有任何其他示例破坏了此答案,请告诉我。

    【讨论】:

    • 我必须指出,我已经假设] 不会在a 标签内的其他任何地方找到。如果存在该字符的可能性存在,则此正则表达式将不起作用。
    【解决方案6】:
    /<a\b[^>]*href\s*=\s*"(\[nggallery id=[^"]+\])".*?<\/a>/i
    

    这会将短代码[nggallery id=XXX] 放入第 1 组,然后将匹配项替换为第 1 组的内容。

    注意:这假定 HTML 格式合理,适用通常的免责声明。

    【讨论】:

      【解决方案7】:

      Fab Sa 的正则表达式 &lt;a.*(\[nggallery[^\]+]*\]).*?&lt;\/a&gt; 在一行上有多个 &lt;a&gt; 标签时会吞噬所有内容,因为开头的 .* 不受限制,它将匹配不同的 &lt;a&gt; 标签。

      通过限制允许的字符,你可以在某种程度上匹配你想要的:

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

      我在a 之后强制使用至少一个空格,以确保它不匹配其他一些标签,以及一些额外的限制。

      无论如何,如果您发现它在某些极端情况下不起作用,您就只能靠自己了。使用正则表达式操作 HTML 通常是个坏主意。

      【讨论】:

      • 谢谢,我意识到带有 html 的正则表达式是非常有问题的。但是,如果我使用 html 解析器,我需要运行某种 php 循环或 ajax 来访问每个 WordPress 帖子。您的正则表达式仍会删除短代码;但是什么 2 个正则表达式,每个都单独运行?一个从短代码的左侧剥离 html,然后另一个从右侧剥离?
      • 啊,我的错;在 Wordpress 中使用正则表达式时,这确实有效;但在 BBEdit 中没有。可能是 BBedit 中正则表达式的不完整实现?将在 WordPress 内容上测试这种不同的方式。谢谢!
      • 这似乎工作得很好,仍然需要测试更多的实例。谢谢!
      【解决方案8】:

      这是怎么回事?

      (?&lt;=nggallery\sid=xx]"&gt;).*(?=&lt;\/a&gt;)

      使用全局和单行作为修饰符(-g 和 -s)。这匹配&lt;a href="[nggallery id=xx]"&gt;&lt;/a&gt; 之间的所有内容。我不确定我是否正确理解了您的问题......但是这个 RegEx 符合我刚才的描述。

      【讨论】:

      • 这不是他问的。使用标志 s 它将保留一行,并且您不保存 nggallery 部分+检查另一个答案。
      • 您的正则表达式与第一个 &lt;a href="[nggallery id=xx]"&gt; (第 1 行)不匹配是否有原因。在我的 RegEx101 引擎中,它没有显示你的匹配那个,这对我来说似乎是一个错误。
      • 太棒了!干得好。我不知道为什么我的引擎只将最后两个与您的 RegEx 匹配,但它现在可以工作了。奇怪...
      【解决方案9】:

      你可以使用这个正则表达式

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

      全局(标记 g)。此正则表达式将匹配一个链接并保存 [nggallery ...] 部分。您可以将所有匹配替换为 $1 以保留保存的 [nggallery ...] 部分。

      我已经在线更新了你的正则表达式:https://www.regex101.com/r/rL8wP1/4

      PS:在这个解决方案中[nggallery ...] 不需要像 href 这样的特定属性。如果你想强制这样做,你可以使用&lt;a.*href\="(\[nggallery[^\]+]*\])".*?&lt;\/a&gt;

      【讨论】:

      • 你打败了我!另外,友情提醒YOU CANNOT PARSE HTML WITH REGEX。但是,这个答案应该适合您的目的
      • 我同意。使用真正的解析器解析 html 比使用正则表达式更好,但正如您所说,我只是回复,有时正则表达式更容易和/或更快。
      • Fab Sa 和 Zack,谢谢!我读过你不能用正则表达式解析 HTML,但我想我只是想删除标记。问题是正则表达式在 regex101 上工作正常,但是当我尝试在我的 RegEx 插件中运行以与 WordPress 内容一起使用时,我得到一个“没有结尾匹配分隔符'>'”的错误。正则表达式是否需要是一行而不是替换 $1?
      • 你应该使用像/myregex/这样的分隔符。你的代码行是什么样的?
      • 我建议使用您的正则表达式中未使用的分隔符。如果您的分隔符在您的正则表达式中,您需要在每个实例中转义它。这是关于正则表达式分隔符的 PHP 文档,不确定您是否使用 PHP,php.net/manual/en/regexp.reference.delimiters.php.
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-11-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-01-29
      相关资源
      最近更新 更多