leeming Posted April 18, 2007 Share Posted April 18, 2007 Im trying to create a copy of BBS codes. i know i can do replace on these type of tags, but i have come across an error, and would like to understand it. //BOLD text $tag = '/(\[b\])(.*)(\[\/b\])/'; $html = '<b>${2}</b>'; $text = preg_replace($tag, $html, $text); The problem i have with the above is... [b]bold[/b] normal [b]bold[/b] Shows as: bold[ /b ] norma [ b ]bold Just without the obvious spaces Basicly, it is catching the 1st bold tag, and matching it with the last one it can find (thus the middle is missed out) Quote Link to comment Share on other sites More sharing options...
MadTechie Posted April 18, 2007 Share Posted April 18, 2007 here <?php $string = 'Hello [b] how are you [/b] sorry'; $pattern[] = '/\[b\](.*)\[\/b\]/'; $replacement[] = '<B>${1}</B>'; echo preg_replace($pattern, $replacement, $string); ?> EDIT: this will catch [b] how are you [/b] and replace with <B>(.*)</B> in this case <B>how are you</B> no need to capture the [b]'s by them selfs as your replacing them.. i added an extended one below just for fun i have been playing with RegEx and a may write my own BBCode when time permits sounds like good pratice Quote Link to comment Share on other sites More sharing options...
MadTechie Posted April 18, 2007 Share Posted April 18, 2007 extended <?php $string = 'Hello [b] how are you [i] how are you [u] how are you [/u][/i][/b] sorry'; $pattern[] = '/\[b\](.*)\[\/b\]/'; $pattern[] = '/\[i\](.*)\[\/i\]/'; $pattern[] = '/\[u\](.*)\[\/u\]/'; $replacement[] = '<B>${1}</B>'; $replacement[] = '<I>${1}</I>'; $replacement[] = '<U>${1}</U>'; echo preg_replace($pattern, $replacement, $string); ?> Quote Link to comment Share on other sites More sharing options...
Glyde Posted April 18, 2007 Share Posted April 18, 2007 The way you want this to work requires (as far as I know) you to individually locate each one. Lucky enough for you, I have already written a script that can do this, and it works pretty well as far as I can tell. <?php class bbcode { /** * List of supported tags * */ var $_tagList = array( 'b' => '<b>{TEXT}</b>', 'u' => '<u>{TEXT}</u>', 'i' => '<i>{TEXT}</i>', 'color' => '<span style="color: {OPT}">{TEXT}</span>' ); /** * List of tags with an optional attribute (so you can make [color=whatever]sdf[/color] for example * */ var $_attrList = array( 'color' => "((#[0-9A-F]{3,6})|([A-Z\-]+))" ); /** * Convert from a standard input to HTML * * @param string $input * @return string */ function toHTML($input) { // Loop through the taglist and convert all foreach ( $this->_tagList as $tagKey=>$tagHTML ) { $tagOpen = "[{$tagKey}]"; $tagClose = "[/{$tagKey}]"; // Find the first instance of the current tag item if (!$this->_attrList[$tagKey]) { while ((stripos($input, $tagOpen) !== FALSE) && (strripos($input, $tagClose) !== FALSE)) { $position = stripos($input, $tagOpen); if ($position === FALSE) continue; $endposition = strripos($input, $tagClose, $position); if ($endposition === FALSE) continue; // Replace the text $newText = substr($input, $position + strlen($tagOpen), $endposition - ($position + strlen($tagOpen))); $newText = str_replace("{TEXT}", $newText, $tagHTML); $input = substr($input, 0, $position) . $newText . substr($input, $endposition + strlen($tagClose)); } } else { $tagOpen = "@\[{$tagKey}=".$this->_attrList[$tagKey]."\]@is"; while (preg_match($tagOpen, $input) && (strripos($input, $tagClose) !== FALSE)) { preg_match($tagOpen, $input, $match); $position = stripos($input, $match[0]); if ($position === FALSE) continue; $endposition = strripos($input, $tagClose, $position); if ($endposition === FALSE) continue; // Replace the text $newText = substr($input, $position + strlen($match[0]), $endposition - ($position + strlen($match[0]))); $tagHTML = str_replace("{OPT}", $match[1], $tagHTML); $newText = str_replace("{TEXT}", $newText, $tagHTML); $input = substr($input, 0, $position) . $newText . substr($input, $endposition + strlen($tagClose)); } } } } } ?> I haven't really optimized this code yet, but it works. Anyways, I think you can figure out how it works, if not, let me know. Quote Link to comment Share on other sites More sharing options...
leeming Posted April 18, 2007 Author Share Posted April 18, 2007 I thank you for the help, but... does not fix any thing... my code still takes the 1st and last (ignoring middle tags) and applying formatting to the whole lot. But i may add, this seems to be only in sections (maybe lines?) I am not fimilar with the syntax, which is why i was enclosing the [ b ] tags (i got hold of the bbs for [ url ] and changed it to do the rest of the tags for myself) Quote Link to comment Share on other sites More sharing options...
leeming Posted April 18, 2007 Author Share Posted April 18, 2007 The way you want this to work requires (as far as I know) you to individually locate each one. Lucky enough for you, I have already written a script that can do this, and it works pretty well as far as I can tell. <?php class bbcode { /** * List of supported tags * */ var $_tagList = array( 'b' => '<b>{TEXT}</b>', 'u' => '<u>{TEXT}</u>', 'i' => '<i>{TEXT}</i>', 'color' => '<span style="color: {OPT}">{TEXT}</span>' ); /** * List of tags with an optional attribute (so you can make [color=whatever]sdf[/color] for example * */ var $_attrList = array( 'color' => "((#[0-9A-F]{3,6})|([A-Z\-]+))" ); /** * Convert from a standard input to HTML * * @param string $input * @return string */ function toHTML($input) { // Loop through the taglist and convert all foreach ( $this->_tagList as $tagKey=>$tagHTML ) { $tagOpen = "[{$tagKey}]"; $tagClose = "[/{$tagKey}]"; // Find the first instance of the current tag item if (!$this->_attrList[$tagKey]) { while ((stripos($input, $tagOpen) !== FALSE) && (strripos($input, $tagClose) !== FALSE)) { $position = stripos($input, $tagOpen); if ($position === FALSE) continue; $endposition = strripos($input, $tagClose, $position); if ($endposition === FALSE) continue; // Replace the text $newText = substr($input, $position + strlen($tagOpen), $endposition - ($position + strlen($tagOpen))); $newText = str_replace("{TEXT}", $newText, $tagHTML); $input = substr($input, 0, $position) . $newText . substr($input, $endposition + strlen($tagClose)); } } else { $tagOpen = "@\[{$tagKey}=".$this->_attrList[$tagKey]."\]@is"; while (preg_match($tagOpen, $input) && (strripos($input, $tagClose) !== FALSE)) { preg_match($tagOpen, $input, $match); $position = stripos($input, $match[0]); if ($position === FALSE) continue; $endposition = strripos($input, $tagClose, $position); if ($endposition === FALSE) continue; // Replace the text $newText = substr($input, $position + strlen($match[0]), $endposition - ($position + strlen($match[0]))); $tagHTML = str_replace("{OPT}", $match[1], $tagHTML); $newText = str_replace("{TEXT}", $newText, $tagHTML); $input = substr($input, 0, $position) . $newText . substr($input, $endposition + strlen($tagClose)); } } } } } ?> I haven't really optimized this code yet, but it works. Anyways, I think you can figure out how it works, if not, let me know. The class looks impressive but, i would like to add that this code i have custom tags, due it been made for some one (its part of my coursework, even though i use php quite a bit any way). And also i'd have to document all this external code. (like previously said, im wanting to understand why it is doing this... i can still use str_replace) Quote Link to comment Share on other sites More sharing options...
Glyde Posted April 18, 2007 Share Posted April 18, 2007 Well you can add as many as you want to the array assuming the tags are formed such as: [b ]. While that code isn't exactly documented, you can feel free to use it if you want, or, you can just check out how I used stripos and strripos, but this might not give you the desired output. This would take: Some [b]sample[/b] [b]string[/b] And make it: Some <b>sample[/b] [b] string</b> As stated, I haven't really fixed this function perfectly...But the reason it works as shown above is because that's how I intended it to work in order to deal with tags correctly. Quote Link to comment Share on other sites More sharing options...
leeming Posted April 18, 2007 Author Share Posted April 18, 2007 ... This would take: Some [b]sample[/b] [b]string[/b] And make it: Some <b>sample[/b] [b] string</b> ... exactly what im trying to explain... oh well, i will just use a simple string replace, and still wonder why i get that error Quote Link to comment Share on other sites More sharing options...
Glyde Posted April 18, 2007 Share Posted April 18, 2007 str_replace works fine, just remember you won't have the functionality of tags such as [ /color] Quote Link to comment Share on other sites More sharing options...
leeming Posted April 22, 2007 Author Share Posted April 22, 2007 Nope i am now forced to do this function for one of my custom tags //References $tag = '/\[ref\](.*)\[\/ref\]/'; $html = '<sup><a href="#ref${1}">[${1}]</a></sup>'; $text = preg_replace($tag, $html, $text); It is an page to add articles, and [ref] just anchors to the bottom where the references are all listed (by number) i get the same annoying output as before... text [ref]1[/ref] middle [ref]2[/ref] end which outputs text <sup><a href="#ref1[/ref] middle [ref]2">[1[/ref] middle [ref]2]</a></sup> end is there no way to get preg_replace (or similar function) to go thru left to right instead of skipping to the last tag? Quote Link to comment Share on other sites More sharing options...
MadTechie Posted April 22, 2007 Share Posted April 22, 2007 if its just numbers then you could use <?php $string = 'text [ref]1[/ref] middle [ref]2[/ref] end'; $pattern[] = '/\[ref\]([\d]*)\[/ref\]/'; $replacement[] = '<sup><a href="#ref${1}">[${1}]</a></sup>'; echo preg_replace($pattern, $replacement, $string); ?> Quote Link to comment Share on other sites More sharing options...
MadTechie Posted April 22, 2007 Share Posted April 22, 2007 oh yeah if the ref's are single words (no spaces) this should work <?php $string = 'text [ref]1[/ref] middle [ref]2[/ref] end'; $pattern[] = '/\[ref\](\w*)\[\/ref\]/'; $replacement[] = '<sup><a href="#ref${1}">[${1}]</a></sup>'; echo preg_replace($pattern, $replacement, $string); ?> Quote Link to comment Share on other sites More sharing options...
MadTechie Posted April 22, 2007 Share Posted April 22, 2007 if its just numbers then you could use <?php $string = 'text [ref]1[/ref] middle [ref]2[/ref] end'; $pattern[] = '/\[ref\](\d*)\[/ref\]/'; $replacement[] = '<sup><a href="#ref${1}">[${1}]</a></sup>'; echo preg_replace($pattern, $replacement, $string); ?> Quote Link to comment Share on other sites More sharing options...
Guest prozente Posted April 23, 2007 Share Posted April 23, 2007 use the ungreedy modifier <?php $text = 'text [ref]1[/ref] middle [ref]2[/ref] end'; $tag = '/\[ref\](.*)\[\/ref\]/U'; $html = '<sup><a href="#ref${1}">[${1}]</a></sup>'; $text = preg_replace($tag, $html, $text); ?> Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.