我一直在摔跤這一段時間。我知道這是很多代碼,但我不知道問題出在哪裏,似乎無法縮小它的範圍。我會賞賜它。問題與strtok()
我寫了這個類來解析bbcodes。它主要使用strtok(),除非你把兩個標籤緊挨着放在一起,否則這個類很好用,我不能爲了我的生活找出原因。
例如[b] [i]test1[/i] [/b]
結果爲<strong> <em>test1</em> </strong>
。 還有[b][i]test1[/i][/b]
結果爲<strong>i]test1/b]</strong>
。 最後一個</strong>
標籤僅存在於此處,因爲解析器自動關閉標籤,因此無法在字符串中找到結束標籤。它完全錯過了[i]
和[/b]
標籤。
下面是類以及它用於設置各種bb代碼的一個子類。子類基本上只是一個沒有行爲的數據結構。
<?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;
}
}
?>
編輯
通過創建符號化下面的類固定。
<?php
// unlike PHP's strtok() function, this class will not skip over empty tokens.
class Lev_TextProcessor_Tokenizer {
protected $string;
public function __construct($string) {
$this->string = $string;
}
public function getToken($token) {
$segment_length = strcspn($this->string, $token);
$token = substr($this->string, 0, $segment_length);
$this->string = substr($this->string, $segment_length + 1);
return $token;
}
}
?>
我得到了'b] test1/b]'而不是。 – alex
@alex奇怪。也許這是因爲我在我的實際輸入測試字符串的開頭有一些空格。 – dqhendricks
是的,在開始的空白給你的原始示例它無法正常工作。 – alex