合并 PHP 中标签的重复属性

Combining duplicate attributes from a tag in PHP

我需要将字符串 This <span style="font-size: 16px;" style="color: red;">is</span> a test. 转换为 This <span style="font-size: 16px; color: red;">is</span> a test.

也有可能有两个以上的匹配项,或者可能有一个 style,然后是一个 class,然后是另一个 style,然后是 styles 需要合并。他们不会总是 spans

不幸的是,Tidy 不是一个选项,因为它在清洁方面比这个项目可以容纳的更过分。

使用 DOM 文档路由将不起作用,因为多个样式属性无效,因此它只获取第一个的内容。

我想用 preg_replace 做到这一点,但事实证明,仅从一个标签中获取匹配项非常困难。

如果它能让事情变得更简单,它们就以嵌套标签开始。我有一个 preg_replace 从那里组合它们并给出这个输出。

我同意上面的评论,最好的解决方案是首先防止这种情况,但回答你的问题:这个函数将组合给定字符串中的所有样式属性。只需确保一次只传递一个标签。标记中有多少其他属性并不重要,顺序也不重要。它将所有样式属性合并到第一个样式值中,然后删除所有其他样式属性:

/**
 * @param string $str
 * @return string
 */
function combineStyles($str)
{
    $found = preg_match_all("/style=\"([^\"]+)\"/", $str, $matches);
    if ($found)
    {
        $combined = 'style="' . implode(';', $matches[1]) . '"';
        $patterns = $matches[0];
        $replace = array_pad(array($combined), count($matches[0]), '');
        $str = str_replace($patterns, $replace, $str);
    }
    return $str;
}

等等,我刚刚意识到它不适用于 style="" id="" style=""

<?php
$str = 'This <span  style="font-size: 16px"  style="color: red;">is</span> a test. This <span  style="font-size: 16px;"  style="color: red;">is</span> a test.';

while (preg_match('/"\s+style="/', $str, $matches))
{
    $pos = strpos($str, $matches[0]);
    $prev = substr($str, 0, $pos);
    if (substr(trim($prev), -1) != ";")
        $prev .= ";";
    $str = $prev.substr($str, $pos+strlen($matches[0]));
}
?>

在 Visual Studio 2012 年的快速替换中使用 .Net 正则表达式,这个表达式对我有用:

Find:
style\s*=\s*(?<q2>['"])(?<w1>(?:(?!\k<q2>).)*?);?\k<q2>\s*(?<c>[^<>]*)\s*style\s*=\s*(?<q2>['"])(?<w2>(?:(?!\k<q2>).)*?);?\k<q2>

Replace:
style="${w1};${w2};" ${c}

备注: 1.这一次只会合并两个style属性。如果单个标签中有多个,则需要多次运行。 2.两个样式属性之间的任何内容都将放在第一个样式属性之后(这是合并后的样式属性将放置的位置)

说明

Find:

style           # match a style attribute
\s*             # match any optional white space
=               # match equals sign
\*              # match any optional white space
(?<q2>['"])     # match either a single or double quote and stored in named capture 'q'
(?<w1>          # start capture of first style attribute's content
(?:             # start non-capturing match
(?!\k<q2>)      # negative look-ahead to prevent matching on this attribute's quote
.)*?            # end non-capturing match with minimal, 0-many quantifier
)               # end capture of first style attribute's content
;?              # place trailing semi-colon (if present) outside the capture
\k<q2>          # match closing quote

\s*             # match white space
(?<c>[^<>]*)    # capture content between style attributes
\s*             # match white space

...             # repeat the above for a second style attribute
                #    except that the second style's capture is named 'w2'

Replacement:
style="         # start merged style attribute
${w1};          # place first style attribute's content
${w2};          # place second style attribute's content
"               # finish merge style attribute
 ${c}           # restore any content found between the two style attributes