Php strtok()的问题
我一直在努力解决这个问题有一段时间了。我知道有很多代码要看,但我不知道问题出在哪里,似乎无法缩小范围。我会悬赏的 我编写这个类是为了解析BBCODE。它主要使用strtok(),这个类工作得很好,除非你把两个标记放在一起,我一辈子都不知道为什么 例如,Php strtok()的问题,php,text-processing,bbcode,strtok,Php,Text Processing,Bbcode,Strtok,我一直在努力解决这个问题有一段时间了。我知道有很多代码要看,但我不知道问题出在哪里,似乎无法缩小范围。我会悬赏的 我编写这个类是为了解析BBCODE。它主要使用strtok(),这个类工作得很好,除非你把两个标记放在一起,我一辈子都不知道为什么 例如,[b][i]test1[/i][/b][/code>会导致test1。 然而,[b][i]test1[/i][/b][/code>会导致i]test1/b][/strong>。 最后一个标记仅在其中,因为解析器会自动关闭它在字符串中找不到的标记。它
[b][i]test1[/i][/b][/code>会导致test1
。
然而,[b][i]test1[/i][/b][/code>会导致i]test1/b][/strong>
。
最后一个
标记仅在其中,因为解析器会自动关闭它在字符串中找不到的标记。它完全忽略了[i]
和[/b]
标记
下面是用于设置各种bbcodes的类和子类。子类基本上只是一个没有行为的数据结构
<?php
// beware images can contain any url/any get request. beware of csrf
class Lev_TextProcessor_Extension_BbCode {
protected $elements = array();
protected $openTags = array();
public function __construct() {
$this->elements['b'] = new Lev_TextProcessor_Extension_BbCode_Element('<strong>', '</strong>');
$this->elements['i'] = new Lev_TextProcessor_Extension_BbCode_Element('<em>', '</em>');
$this->elements['u'] = new Lev_TextProcessor_Extension_BbCode_Element('<span style="text-decoration: underline;">', '</span>');
$this->elements['s'] = new Lev_TextProcessor_Extension_BbCode_Element('<span style="text-decoration: line-through;">', '</span>');
$this->elements['size'] = new Lev_TextProcessor_Extension_BbCode_Element('<span style="font-size: ', '</span>', 'px;">');
$this->elements['color'] = new Lev_TextProcessor_Extension_BbCode_Element('<span style="color: ', '</span>', ';">');
$this->elements['center'] = new Lev_TextProcessor_Extension_BbCode_Element('<div style="text-align: center;">', '</div>', '', true, true, false);
$this->elements['url'] = new Lev_TextProcessor_Extension_BbCode_Element('<a href="', '</a>', '">');
$this->elements['email'] = new Lev_TextProcessor_Extension_BbCode_Element('<a href="mailto:', '</a>', '">');
$this->elements['img'] = new Lev_TextProcessor_Extension_BbCode_Element('<img src="', '" alt="" />', '', false, false, true);
$this->elements['youtube'] = new Lev_TextProcessor_Extension_BbCode_Element('<object width="400" height="325"><param name="movie" value="http://www.youtube.com/v/{param}"></param><embed src="http://www.youtube.com/v/', '" type="application/x-shockwave-flash" width="400" height="325"></embed></object>', '', false, false, false);
$this->elements['code'] = new Lev_TextProcessor_Extension_BbCode_Element('<pre><code>', '</code></pre>', '', true, false, false);
}
public function processText($input) {
// pre processing
$input = htmlspecialchars($input, ENT_NOQUOTES);
$input = nl2br($input);
$input = str_replace(array("\n", "\r"), '', $input);
// start main processing
$output = '';
$allow_child_tags = true;
$allow_child_quotes = true;
$string_segment = strtok($input, '[');
do {
// check content for quotes
if ($allow_child_quotes === false) {
if (strpos($string_segment, '"') === false) {
$output .= $string_segment;
}
} else {
// add content to output
$output .= $string_segment;
}
$tag_contents = strtok(']');
if (strpos($tag_contents, '/') === 0) {
// closing tag
$tag = substr($tag_contents, 1);
if (isset($this->elements[$tag]) === true && array_search($tag, $this->openTags) !== false) {
// tag found
do {
// close tags till matching tag found
$last_open_tag = array_pop($this->openTags);
$output .= $this->elements[$last_open_tag]->htmlAfter;
} while ($last_open_tag !== $tag);
$allow_child_tags = true;
$allow_child_quotes = true;
}
} else {
// opening tag
// separate tag name from argument if there is one
$equal_pos = strpos($tag_contents, '=');
if ($equal_pos === false) {
$tag_name = $tag_contents;
} else {
$tag_name = substr($tag_contents, 0, $equal_pos);
$tag_argument = substr($tag_contents, $equal_pos + 1);
}
if (isset($this->elements[$tag_name]) === true) {
// tag found
if (($this->elements[$tag_name]->allowParentTags === true || count($this->openTags) === 0) && $allow_child_tags === true) {
// add tag to open tag list and set flags
$this->openTags[] = $tag_name;
$allow_child_tags = $this->elements[$tag_name]->allowChildTags;
$allow_child_quotes = $this->elements[$tag_name]->allowChildQuotes;
$output .= $this->elements[$tag_name]->htmlBefore;
// if argument exists
if ($equal_pos !== false) {
if (strpos($tag_argument, '"') === false) {
$output .= $tag_argument;
}
$output .= $this->elements[$tag_name]->htmlCenter;
}
}
}
}
$string_segment = strtok('[');
} while ($string_segment !== false);
// close left over tags
while ($tag = array_pop($this->openTags)) {
$output .= $this->elements[$tag]->htmlAfter;
}
return $output;
}
}
?>
<?php
class Lev_TextProcessor_Extension_BbCode_Element {
public $htmlBefore;
public $htmlAfter;
public $htmlCenter;
public $allowChildQuotes;
public $allowChildTags;
public $allowParentTags;
public function __construct($html_before, $html_after, $html_center = '', $allow_child_quotes = true, $allow_child_tags = true, $allow_parent_tags = true) {
if ($allow_child_quotes === false && $allow_child_tags === true) throw new Lev_TextProcessor_Exception('You may not allow child tags if you do not allow child quotes.');
$this->htmlBefore = $html_before;
$this->htmlAfter = $html_after;
$this->htmlCenter = $html_center;
$this->allowChildQuotes = $allow_child_quotes;
$this->allowChildTags = $allow_child_tags;
$this->allowParentTags = $allow_parent_tags;
}
}
?>
“,”,真,假,假);
}
公共函数processText($input){
//预处理
$input=htmlspecialchars($input,ENT_NOQUOTES);
$input=nl2br($input);
$input=str_replace(数组(“\n”,“\r”),”$input);
//启动主处理
$output='';
$allow\u child\u tags=true;
$allow\u child\u quotes=true;
$string_segment=strtok($input,“[”);
做{
//检查引用的内容
if($allow_child_quotes===false){
if(strpos($string_segment,“')==false){
$output.=$string\u段;
}
}否则{
//将内容添加到输出
$output.=$string\u段;
}
$tag_contents=strtok(']');
if(strpos($tag_contents,'/')==0){
//结束语
$tag=substr($tag_内容,1);
if(isset($this->elements[$tag])==true&&array\u搜索($tag,$this->openTags)!==false){
//找到标签
做{
//关闭标记,直到找到匹配的标记
$last\u open\u tag=array\u pop($this->openTags);
$output.=$this->elements[$last\u open\u tag]->htmlAfter;
}while($last\u open\u tag!==$tag);
$allow\u child\u tags=true;
$allow\u child\u quotes=true;
}
}否则{
//开场白
//如果有标记名,请将其与参数分开
$equal_pos=strpos($tag_contents,'=');
如果($equal_pos==false){
$tag\u name=$tag\u contents;
}否则{
$tag\u name=substr($tag\u contents,0,$equal\u pos);
$tag_argument=substr($tag_contents,$equal_pos+1);
}
if(isset($this->elements[$tag\u name])==true){
//找到标签
if($this->elements[$tag_name]->allowParentTags===true | | count($this->openTags==0)&&&$allow_child_tags==true){
//将标记添加到打开的标记列表并设置标记
$this->openTags[]=$tag\u name;
$allow\u child\u tags=$this->elements[$tag\u name]->allowChildTags;
$allow\u child\u quotes=$this->elements[$tag\u name]->allowChildQuotes;
$output.=$this->elements[$tag\u name]->htmlBefore;
//如果参数存在
如果($equal_pos!==false){
if(strpos($tag_参数“,”)==false){
$output.=$tag\u参数;
}
$output.=$this->elements[$tag\u name]->htmlCenter;
}
}
}
}
$string_段=strtok('[');
}while($string_段!==false);
//关闭剩余标签
而($tag=array\u pop($this->openTags)){
$output.=$this->elements[$tag]->htmlAfter;
}
返回$output;
}
}
?>
编辑
通过创建以下用于标记化的类进行修复
<?
$data1 = strtok('[b][i]test1[/i][/b]','[');
$data2 = strtok(']');
$data3 = strtok('[');
$data4 = strtok(']');
$data5 = strtok('[');
$data6 = strtok(']');
var_dump($data1, $data2,$data3, $data4, $data5, $data6);
/*
OUTPUT
string(2) "b]"
string(1) "i"
string(5) "test1"
string(2) "/i"
string(3) "/b]"
bool(false)
* /
?>
虽然我不认为这是真正的解决方案,但这似乎是我要表达观点的唯一途径
它可能是通过strtok()
的工作方式获得您想要的结果
虽然不是完美的,但我能够通过以下方法获得接近您预期的结果:
正如我所说,它并不完美,但看到它可能会帮助您处理此解决方案。我个人从未使用preg_match()
处理过这种类型的BBCode解析,而是使用b]test1/b]
。@alex strange。可能是因为我在实际输入测试字符串的开头有一些空格。是的,开头的空格给出了它不起作用的原始示例。在我看来,$string\u segment=strtok('[')行是谁;
正在处理事情。从我在PHP手册中读到的关于strtok的内容来看,它在标记中没有包含分隔符,您使用的是[作为分隔符。@JRSofty我先使用[,然后使用]。我不明白您的意思。preg match的问题是[b][I][b][I],嵌套不正确。还有这个[b],未关闭的标记不会自动关闭。然后是速度。您的示例很有帮助,因为它缩小了复制所需的代码范围。似乎跳过了第一个“[”,然后是probl
<?
$data1 = strtok('[b][i]test1[/i][/b]','[');
$data2 = strtok(']');
$data3 = strtok('[');
$data4 = strtok(']');
$data5 = strtok('[');
$data6 = strtok(']');
var_dump($data1, $data2,$data3, $data4, $data5, $data6);
/*
OUTPUT
string(2) "b]"
string(1) "i"
string(5) "test1"
string(2) "/i"
string(3) "/b]"
bool(false)
* /
?>