Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/regex/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
PHP PREG_REPLACE根据检查的顺序返回错误结果_Php_Regex_Preg Replace - Fatal编程技术网

PHP PREG_REPLACE根据检查的顺序返回错误结果

PHP PREG_REPLACE根据检查的顺序返回错误结果,php,regex,preg-replace,Php,Regex,Preg Replace,我在PHP的preg_replace函数和一些正则表达式模式中偶然发现了一个非常奇怪的错误。我试图做的是替换用括号分隔的自定义标记,并将它们转换为HTML。正则表达式必须考虑保留在输出HTML中的自定义“fill”标记,以便在页面加载时可以动态替换它(例如,替换为站点名称) 每个正则表达式模式都会自行工作,但由于某些原因,如果先选中前面的某个其他模式,则其中一些模式会提前退出函数。当我偶然发现这一点时,我使用preg_match和foreach循环在继续之前检查模式,并在发现结果时返回结果——因

我在PHP的preg_replace函数和一些正则表达式模式中偶然发现了一个非常奇怪的错误。我试图做的是替换用括号分隔的自定义标记,并将它们转换为HTML。正则表达式必须考虑保留在输出HTML中的自定义“fill”标记,以便在页面加载时可以动态替换它(例如,替换为站点名称)

每个正则表达式模式都会自行工作,但由于某些原因,如果先选中前面的某个其他模式,则其中一些模式会提前退出函数。当我偶然发现这一点时,我使用preg_match和foreach循环在继续之前检查模式,并在发现结果时返回结果——因此假设每个模式看起来都很新鲜

这也没用

检查代码:

function replaceLTags($originalString){
    $patterns = array(
                '#^\[l\]([^\s]+)\[/l\]$#i' => '<a href="$1">$1</a>',
                '#^\[l=([^\s]+)]([^\[]+)\[/l\]$#i'=> '<a href="$1">$2</a>',
                '#^\[l=([^\s]+) title=([^\[]+)]([^\[]+)\[/l\]$#i' => '<a href="$1" title="$2">$3</a>',
                '#^\[l=([^\s]+) rel=([^\[]+)]([^\[]+)\[/l\]$#i' => '<a href="$1" rel="$2">$3</a>',
                '#^\[l=([^\s]+) onClick=([^\[]+)]([^\[]+)\[/l\]$#i' => '<a href="$1" onClick="$2">$3</a>',
                '#^\[l=([^\s]+) style=([^\[]+)]([^\[]+)\[/l\]$#i' => '<a href="$1" style="$2">$3</a>',
                '#^\[l=([^\s]+) onClick=([^\[]+) style=([^\[]+)]([^\[]+)\[/l\]$#i' => '<a href="$1" onClick="$2" style="$3">$4</a>',
                '#^\[l=([^\s]+) class=([^\[]+) style=([^\[]+)]([^\[]+)\[/l\]$#i' => '<a href="$1" class="$2" style="$3">$4</a>',
                '#^\[l=([^\s]+) class=([^\[]+) rel=([^\[]+)] target=([^\[]+)]([^\[]+)\[/l\]$#i' => '<a href="$1" class="$2" rel="$3" target="$4">$5</a>'
            );

    foreach ($patterns as $pattern => $replace){
        if (preg_match($pattern, $originalString)){
            return preg_replace($pattern, $replace, $originalString);
        }
    }
}

$string = '[l=[site_url]/site-category/ class=hello rel=nofollow target=_blank]Hello there[/l]';

echo $alteredString = $format->replaceLTags($string);
<a href="[site_url">/site-category/ class=hello rel=nofollow target=_blank]Hello there</a>
<a href="[site_url]/site-category/" class="hello" rel="nofollow" target="_blank">Hello there</a>
函数replaceLTags($originalString){
$patterns=数组(
“#^\[l\]([^\s]+)\[/l\]$#i'=>”,
“#^\[l=([^\s]+)]([^\[]+)\[/l\]$\i'=>”,
“#^\[l=([^\s]+)title=([^\[]+)]([^\[]+)\[/l\]$i'=>”,
“#^\[l=([^\s]+)rel=([^\[]+)]([^\[]+)\[/l\]$i'=>”,
“#^\[l=([^\s]+)onClick=([^\[]+)]([^\[]+)\[/l\]$i'=>”,
“#^\[l=([^\s]+)style=([^\[]+)]([^\[]+)\[/l\]$i'=>”,
“#^\[l=([^\s]+)onClick=([^\[]+)style=([^\[]+)]([^\[]+)\[/l\]$i'=>”,
“^\[l=([^\s]+)类=([^\[]+)样式=([^\[]+)]([^\[]+)\[/l\]$”,
“#^\[l=([^\s]+)class=([^\[]+)rel=([^\[]+)]target=([^\[]+)]([^\[]+)\[/l\]$i'=>”
);
foreach($patterns as$pattern=>$replace){
if(预匹配($pattern$originalString)){
返回preg_replace($pattern,$replace,$originalString);
}
}
}
$string='[l=[site\u url]/site category/class=hello rel=nofollow target=\u blank]hello there[/l]';
echo$alteredString=$format->replaceLTags($string);
上述“字符串”将显示为:

function replaceLTags($originalString){
    $patterns = array(
                '#^\[l\]([^\s]+)\[/l\]$#i' => '<a href="$1">$1</a>',
                '#^\[l=([^\s]+)]([^\[]+)\[/l\]$#i'=> '<a href="$1">$2</a>',
                '#^\[l=([^\s]+) title=([^\[]+)]([^\[]+)\[/l\]$#i' => '<a href="$1" title="$2">$3</a>',
                '#^\[l=([^\s]+) rel=([^\[]+)]([^\[]+)\[/l\]$#i' => '<a href="$1" rel="$2">$3</a>',
                '#^\[l=([^\s]+) onClick=([^\[]+)]([^\[]+)\[/l\]$#i' => '<a href="$1" onClick="$2">$3</a>',
                '#^\[l=([^\s]+) style=([^\[]+)]([^\[]+)\[/l\]$#i' => '<a href="$1" style="$2">$3</a>',
                '#^\[l=([^\s]+) onClick=([^\[]+) style=([^\[]+)]([^\[]+)\[/l\]$#i' => '<a href="$1" onClick="$2" style="$3">$4</a>',
                '#^\[l=([^\s]+) class=([^\[]+) style=([^\[]+)]([^\[]+)\[/l\]$#i' => '<a href="$1" class="$2" style="$3">$4</a>',
                '#^\[l=([^\s]+) class=([^\[]+) rel=([^\[]+)] target=([^\[]+)]([^\[]+)\[/l\]$#i' => '<a href="$1" class="$2" rel="$3" target="$4">$5</a>'
            );

    foreach ($patterns as $pattern => $replace){
        if (preg_match($pattern, $originalString)){
            return preg_replace($pattern, $replace, $originalString);
        }
    }
}

$string = '[l=[site_url]/site-category/ class=hello rel=nofollow target=_blank]Hello there[/l]';

echo $alteredString = $format->replaceLTags($string);
<a href="[site_url">/site-category/ class=hello rel=nofollow target=_blank]Hello there</a>
<a href="[site_url]/site-category/" class="hello" rel="nofollow" target="_blank">Hello there</a>

什么时候应该显示为:

function replaceLTags($originalString){
    $patterns = array(
                '#^\[l\]([^\s]+)\[/l\]$#i' => '<a href="$1">$1</a>',
                '#^\[l=([^\s]+)]([^\[]+)\[/l\]$#i'=> '<a href="$1">$2</a>',
                '#^\[l=([^\s]+) title=([^\[]+)]([^\[]+)\[/l\]$#i' => '<a href="$1" title="$2">$3</a>',
                '#^\[l=([^\s]+) rel=([^\[]+)]([^\[]+)\[/l\]$#i' => '<a href="$1" rel="$2">$3</a>',
                '#^\[l=([^\s]+) onClick=([^\[]+)]([^\[]+)\[/l\]$#i' => '<a href="$1" onClick="$2">$3</a>',
                '#^\[l=([^\s]+) style=([^\[]+)]([^\[]+)\[/l\]$#i' => '<a href="$1" style="$2">$3</a>',
                '#^\[l=([^\s]+) onClick=([^\[]+) style=([^\[]+)]([^\[]+)\[/l\]$#i' => '<a href="$1" onClick="$2" style="$3">$4</a>',
                '#^\[l=([^\s]+) class=([^\[]+) style=([^\[]+)]([^\[]+)\[/l\]$#i' => '<a href="$1" class="$2" style="$3">$4</a>',
                '#^\[l=([^\s]+) class=([^\[]+) rel=([^\[]+)] target=([^\[]+)]([^\[]+)\[/l\]$#i' => '<a href="$1" class="$2" rel="$3" target="$4">$5</a>'
            );

    foreach ($patterns as $pattern => $replace){
        if (preg_match($pattern, $originalString)){
            return preg_replace($pattern, $replace, $originalString);
        }
    }
}

$string = '[l=[site_url]/site-category/ class=hello rel=nofollow target=_blank]Hello there[/l]';

echo $alteredString = $format->replaceLTags($string);
<a href="[site_url">/site-category/ class=hello rel=nofollow target=_blank]Hello there</a>
<a href="[site_url]/site-category/" class="hello" rel="nofollow" target="_blank">Hello there</a>

但如果将该模式在列表中进一步上移,以便更快地进行检查,它的格式就会正确


我被难住了,因为每次检查字符串时,字符串似乎都会被覆盖,尽管这毫无意义。

您弄乱了正则表达式。如果您在每次迭代中都将字符串打印为:

foreach ($patterns as $pattern => $replace){
    echo "String: $originalString\n";
    if (preg_match($pattern, $originalString)){
        return preg_replace($pattern, $replace, $originalString);
    }
}
您将看到字符串没有被修改。从我的运行中,我注意到第二个正则表达式匹配。我在
preg_match
调用中放置了第三个参数并打印了匹配项。下面是我得到的结果:

Array (
    [0] => [l=[site_url]/site-category/ class=hello rel=nofollow target=_blank]Hello there[/l]
    [1] => [site_url
    [2] => /site-category/ class=hello rel=nofollow target=_blank]Hello there )

下面是一些通用代码,您可以使用它们来减少表达式的数量,您可以从最终字符串中删除任何不允许的标记

<?php

function replaceLTags($originalString) {
    if (preg_match('#^\[l\]([^\s]+)\[/l\]$#i', $originalString)) {
        // match a link with no description or tags
        return preg_replace('#^\[l\]([^\s]+)\[/l\]$#i', '<a href="$1">$1</a>', $originalString);
    } else if (preg_match('#^\[l=([^\s]+)\s*([^\]]*)\](.*?)\[/l\]#i', $originalString, $matches)) {
        // match a link with title and/or tags
        $attribs = $matches[2];
        $attrStr = '';
        if (preg_match_all('#([^=]+)=([^\s\]]+)#i', $attribs, $attribMatches) > 0) {
            $attrStr = ' ';
            for ($i = 0; $i < sizeof($attribMatches[0]); ++$i) {
                $attrStr .= $attribMatches[1][$i] . '="' . $attribMatches[2][$i] . '" ';
            }
            $attrStr = rtrim($attrStr);
        }

        return '<a href="' . $matches[1] . '"' . $attrStr . '>' . $matches[3] . '</a>';
    } else {
        return $originalString;
    }
}

$strings = array(
    '[l]http://www.stackoverflow.com[/l]',
    '[l=[site_url]/site-category/ class=hello rel=nofollow target=_blank]Hello there[/l]',
    '[l=[site_url]/page.php?q=123]Link[/l]',
    '[l=http://www.stackoverflow.com/careers/ target=_blank class=default]Stack overflow[/l]'
);

foreach($strings as $string) {
    $altered = replaceLTags($string);
    echo "{$altered}<br />\n";
}

在我看来,您所做的工作比需要做的多得多。与其对每个可能的属性列表使用单独的正则表达式/替换,为什么不使用
preg\u replace\u callback
在单独的步骤中处理属性呢?例如:

function replaceLTags($originalString){
  return preg_replace_callback('#\[l=((?>[^\s\[\]]+|\[site_url\])+)([^\]]*)\](.*?)\[/l\]#',
                               replaceWithinTags, $originalString);
}

function replaceWithinTags($groups){
  return '<a href="' . $groups[1] . '"' . 
         preg_replace('#(\s+\w+)=(\S+)#', '$1="$2"', $groups[2]) .
         '>' . $groups[3] . '</a>';
}

最棘手的部分是匹配多单词属性值。
(?>\s+[^\s=]+)*
将始终使用下一个标记名(如果有),但前瞻会强制它回溯。通常一次只回溯一个字符,但原子组有效地强制它回溯整个单词,或者根本不回溯。

当前问题的原因有两个:

首先,在适用的正则表达式(数组中的最后一个)中有一个输入错误。它在:
“target=“
”前面有一个无关的右方括号。换句话说,这是:

“#^\[l=([^\s]+)class=([^\[]+)rel=([^\[]+)]target=([^\[]+)]([^\[]+)\[/l\]$\i'

应改为:

“#^\[l=([^\s]+)class=([^\[]+)rel=([^\[]+)target=([^\[]+)]([^\[]+)\[/l\]$\i'

其次,数组中有两个正则表达式都匹配同一个字符串,不幸的是,这两个正则表达式中更具体的一个(上面的正则表达式就是我们想要的)排在第二位。另一个更一般的正则表达式匹配的是数组中的第二个正则表达式:

“#^\[l=([^\s]+)]([^\[]+)\[/l\]$i”

将更通用的正则表达式放在最后,并删除多余的方括号可以解决此问题。以下是应用上述两个更改后修复的原始代码:

函数replaceLTags($originalString){
$patterns=数组(
“#^\[l\]([^\s]+)\[/l\]$#i'=>”,
“#^\[l=([^\s]+)title=([^\[]+)]([^\[]+)\[/l\]$i'=>”,
“#^\[l=([^\s]+)rel=([^\[]+)]([^\[]+)\[/l\]$i'=>”,
“#^\[l=([^\s]+)onClick=([^\[]+)]([^\[]+)\[/l\]$i'=>”,
“#^\[l=([^\s]+)style=([^\[]+)]([^\[]+)\[/l\]$i'=>”,
“#^\[l=([^\s]+)onClick=([^\[]+)style=([^\[]+)]([^\[]+)\[/l\]$i'=>”,
“^\[l=([^\s]+)类=([^\[]+)样式=([^\[]+)]([^\[]+)\[/l\]$”,
“#^\[l=([^\s]+)class=([^\[]+)rel=([^\[]+)target=([^\[]+)]([^\[]+)\[/l\]$i'=>”,
“#^\[l=([^\s]+)]([^\[]+)\[/l\]$\i'=>”
);
foreach($patterns as$pattern=>$replace){
if(预匹配($pattern$originalString)){
返回preg_replace($pattern,$replace,$originalString);
}
}
}
$string='[l=[site\u url]/site category/class=hello rel=nofollow target=\u blank]hello there[/l]';
echo$alteredString=$format->replaceLTags($string);
请注意,这只修复了您的问题中描述的即时特定错误,并没有解决您试图完成的任务中的一些更基本的问题。我为您的后续问题提供了一个更好的解决方案:


但正如其他人所提到的,将两种不同的标记语言混合在一起并使用regex进行处理会带来麻烦。

您真的想在这里使用
return
吗?
ret