PHP编辑字符串的中间部分不起作用?

PHP编辑字符串的中间部分不起作用?,php,string,parsing,scripting,Php,String,Parsing,Scripting,好的,基本上我想做的是创建一种BB代码系统,而不使用正则表达式。我在下面使用的代码似乎可以完美地工作,尽管它不是。基本上,代码应该取一个字符串,从所有[code][/code]块中删除所有的break标记,并将其替换回整个字符串。然后代码应该将[code][/code]标记转换为我正在使用的SyntaxHighlighter脚本的“pre”标记 不幸的是,代码并不是100%完全有效。在某些情况下,它仍然会在[code][/code]块中保留中断标记。我的代码是: <?php $string

好的,基本上我想做的是创建一种BB代码系统,而不使用正则表达式。我在下面使用的代码似乎可以完美地工作,尽管它不是。基本上,代码应该取一个字符串,从所有[code][/code]块中删除所有的break标记,并将其替换回整个字符串。然后代码应该将[code][/code]标记转换为我正在使用的SyntaxHighlighter脚本的“pre”标记

不幸的是,代码并不是100%完全有效。在某些情况下,它仍然会在[code][/code]块中保留中断标记。我的代码是:

<?php
$string = "Hello\n[code]\nCode One\n[/code]\n[code]\nCode Two\n[/code]\n[code]\nCode    Three\n[/code]";
$string = nl2br($string);
$openArray = array();
$closeArray = array();
$original = "";
$newString = "";

$i = 0;
if(strpos($string, "[code]") === 0) {
    array_push($openArray, 0);
}
while($i = strpos($string, "[code]", $i + 1)) {
    array_push($openArray, $i);
}
while($i = strpos($string, "[/code]", $i + 1)) {
    array_push($closeArray, $i + 7);    
}
for($j = 0; $j < count($openArray); $j++) {
    $length = $closeArray[$j] - $openArray[$j];
    $original = substr($string, $openArray[$j], $length);
    $newString = strip_tags($original);
    $string = str_replace($original, $newString, $string);
}
$string = str_replace("[code]", '<pre class="brush: plain">', $string);
$string = str_replace("[/code]", '</pre>', $string);
echo $string;
?>


所有的答案都是非常感谢的,因为我一直在想这有什么不对,我已经尝试了很多不同的方法

我看到的处理过程中的主要问题是,您存储的open和close标记彼此非常独立。然后,您将处理它们,就好像每个代码都属于彼此一样,但这并不能保证,因为您不验证是否有一个结束代码跟在一个开始代码后面,如果不是两个开始或结束代码后面,那么应该会给出一个解析错误

您可以自己编写一个小助手函数,它与strpos一样,返回打开和关闭代码对的下一个位置:

function codepos($string, $code, $offset) {
    $offset = 0;
    if (FALSE === $start = strpos($string, "[$code]", $offset)) {
        return FALSE;
    }
    if (FALSE === $stop = strpos($string, "[/$code]", $start) {
        throw new Exception('Close code not found.');
    }
    if ($next = strpos($string, "[$code]", $start + 1) && $next < $stop) {
        throw new Exception('Double opening detected.');
    } 
    $pos = new stdClass;
    $pos->start = $start;
    $pos->stop = $stop;
    $pos->code = $code;
    return $pos;
}

仅用于学习或内联网工具,甚至不在www上考虑:

您需要考虑:
行可能比字符串缓冲区长。知道您将有一个最大行大小,除非您对其进行编码。

除非您假定输入总是正确的,否则打开标记之前可能的关闭标记和可能丢失的关闭/打开标记的代码。

能够处理以下情况:
State1正在查找一个或多个打开的标记:
没有打开/关闭标签
仅打开标签
首先关闭标记-解析失败
一个或多个匹配的打开/关闭标记(按正确顺序)
一个或多个匹配的打开/关闭标记(按正确顺序)以打开标记结尾
文档结束-正常
状态2正在查找关闭标记:
关闭标记,后跟一个或多个匹配的打开/关闭标记(按正确顺序)
关闭标记,后跟一个或多个匹配的打开/关闭标记(按正确顺序),以打开标记结尾
无结束标记

文档结束-解析失败

@minitech有没有建议OP以正确的方式进行解析?@bsdnoobz:没有。使用
strpos
解析BBCode总是错误的。没有办法修复它。您使用正则表达式时走错了方向。在解析工具集的强大功能下,您应该向上移动,而不是向下移动。您可以找到任意数量的预构建库来解析BBCode,但是如果您想构建自己的库,请使用解析器生成器,而不是
strpos
。我认为仅仅说
strpos
是错误的是不对的。字符串分析并没有错,我看不到有太多的评论者能够很好地解释使用
strpos
@Mark Reed:您建议PHP使用哪种解析器生成器?你有没有用过你自己的一个?谢谢你的回答!我要用你发布的代码玩几分钟。我终于得到了一些可用的代码,但我只是用了一些正则表达式使它工作,刚开始我不想使用正则表达式,因为我想我可以从不用正则表达式的挑战中得到一些乐趣,但我在这方面花的时间比我应该花的时间多了一点,但非常感谢你发布代码并帮助我,伙计:D
$offset = 0;
while($pos = codepos($string, 'code', $offset))
{
    ... process each code-pair.
}