Page 1 of 1

Using regex to do quotes like this forum does

Posted: Tue Nov 29, 2005 5:44 am
by Grim...
So,

Code: Select all

[quote="Grim..."]Blah blah[/quote]
on this forum outputs
Grim... wrote:Blah blah
How's that done then?
I assume you use regex to pull out the stuff between the
and the stuff in with
between, er, quotes ("<-- that sort of quotes).

Posted: Tue Nov 29, 2005 6:07 am
by Grim...
I've done it with substr and explode for now:

Code: Select all

function forumQuotes($text) {
    
    if (stripos($text, "[quote") === FALSE)
    {
        return ($text);
    }
    
    //remove the quote from the text
    $boom = explode("[quote", $text);
    $bang = explode("[/quote]", $boom[1]);
    
    $quote = $bang[0];
    
    $bang = explode("]", $quote); //bang[0] is the username, bang[1] is the quote text
    
    if (substr($bang[0], 0, 1) != "=")
    {
        //no name
        $quote = $bang[1];
    }
    else
    {
        $bang[0] = str_replace("=", "", $bang[0]);
        $bang[0] = str_replace("\"", "", $bang[0]);
        $quote = $bang[0]." says ".$bang[1];
    }
    
    return "<div class=\"quote\">".$quote."</div>";
}
I always use $bang and $boom for my explode arrays ;)

Posted: Tue Nov 29, 2005 6:08 am
by n00b Saibot

Code: Select all

<?php
$str = "[quote="Van Damme"]Jean Claude Van Damme will star with former Miss World Aishwarya Rai in 3rd Asterix and Obelix movie[/quote]";

echo preg_replace("#[quote="(.*?)"](.*?)[/quote]#", "<span class="quote">\\1 wrote:</span><div class="quote-body">\\2</div>", $str);
?>
I seem to be in coding mode today :0)

Posted: Tue Nov 29, 2005 6:28 am
by Grim...

Code: Select all

[quote]This is an unnamed quote[/quote]
comes back as:

[ wrote:
wrote:
]This is an wrote:
nnamd wrote:
wrote:
wrote:
[/ wrote:
wrote:
e]

:?

Posted: Tue Nov 29, 2005 6:32 am
by Grim...
And

Code: Select all

[quote="Grim..."]This is a named quote[/quote]
comes back as:

[ wrote:
wrote:
="Grim..."]This is a nam wrote:
d wrote:
wrote:
[ wrote:
wrote:
wrote:
]
>

Posted: Tue Nov 29, 2005 6:35 am
by n00b Saibot
Using your version, isn't it... my regex didn't even think of unnamed quote :x may be it should be rewritten as #[quote(=\"(.*?)\")?](.*?)[/quote]#

Posted: Tue Nov 29, 2005 6:48 am
by Grim...
It still goes a crazy.

Do I need PHP5 or anything?

Posted: Tue Nov 29, 2005 6:59 am
by Chris Corbyn
Untested...

Code: Select all

function add_quotes($input)
{
    $ret = preg_replace_callback('/\[quote(="([^"]+)")?\](.*?)\[\/quote\]/is', 'parse_bb_quotes', $input);
    return $ret;
}

function parse_bb_quotes($matches)
{
    $header = !empty($matches[2]) ? $matches[2].' wrote:' : 'Quote:';
    
    $ret = <<<END
<div style="width: 500px;"'>
    <div style="font-weight: bold; padding: 2px;">{$header}</div>
    <div style="border: 1px solid #CCCCCC; padding: 2px; background: #FAFAFA;">
        {$matches[3]}
    </div>
</div>

END;

    return $ret;

}

Posted: Tue Nov 29, 2005 7:06 am
by Chris Corbyn
Tested Now... it works flawlessy.

Code: Select all

$string = <<<EOD
Look what I just found....

[quote="d11wtq"]
I'm a genius!
[/quote]

and this... not sure who said it....

[quote]
No he's not!
[/quote]

Cool 
EOD;

echo add_quotes($string);
It ouputs...

Code: Select all

Look what I just found....

<div style="width: 500px;"'>
    <div style="font-weight: bold; padding: 2px;">d11wtq wrote:</div>
    <div style="border: 1px solid #CCCCCC; padding: 2px; background: #FAFAFA;">
        
I'm a genius!

    </div>
</div>


and this... not sure who said it....

<div style="width: 500px;"'>
    <div style="font-weight: bold; padding: 2px;">Quote:</div>

    <div style="border: 1px solid #CCCCCC; padding: 2px; background: #FAFAFA;">
        
No he's not!

    </div>
</div>


Cool :)
Ignore those numbers in my example.... "[ quote:956e70d682="d11wtq"]
I'm a genius!
[/quote ] " ... phpBB appears to be intefering with my code :(

Posted: Tue Nov 29, 2005 7:07 am
by Grim...
That's perfect, D11.

Cheers, both of you :)

Posted: Tue Nov 29, 2005 8:37 am
by John Cartwright
Try running

Code: Select all

$string = 'Look what I just found....

			[quote="d11wtq"]
				Im a genius!
                                [quote="Jcart"] nah uh!!! [/quote]
			[/quote]
			
			and this... not sure who said it....
			
			[quote]
			No hes not!
			[/quote]
			
			Cool ';
This smells stack based parser

Posted: Tue Nov 29, 2005 9:52 am
by Chris Corbyn
Jcart wrote:Try running

Code: Select all

$string = 'Look what I just found....

			[quote="d11wtq"]
				Im a genius!
                                [quote="Jcart"] nah uh!!! [/quote]
			[/quote]
			
			and this... not sure who said it....
			
			[quote]
			No hes not!
			[/quote]
			
			Cool ';
This smells stack based parser
Yes.... to do nested quotes you really need to tokenize and stack and parse ;)

EDIT | Would an example of doing it using a stack based parser help? -- Just a rough example.

Posted: Sun Jan 22, 2006 1:40 pm
by Chris Corbyn
Sorry.... I'm not deliberately bringing this post to life again it has been requested by PM :)

Code: Select all

<?php

error_reporting(E_ALL);

class BBCode
{
	private $source;
	private $output;
	private $tags = array(
		'quote' => '\[quote(?:="([^"]+)")?\]'
	);
	private $tokens = array();
	
	function __construct($input)
	{
		$this->setSource($input);
	}
	
	private function setSource($source)
	{
		$this->source = $source;
	}
	
	//Recursive
	private function tokenize($tag, $text=false, $stack=array(), $recursing=false)
	{
		if (!$text && !$recursing) $text = $this->source;
		elseif (!$text && $recursing) return $stack; //Nothing left to do
		
		$re = '@'.$this->tags[$tag].'|\[/'.$tag.'\]@is'; //Opening tag or closing tag
		
		if (preg_match($re, $text, $matches, PREG_OFFSET_CAPTURE))
		{
			$chunks = $matches[0];
			$offset = 0;
			if ($chunks[1] > 0)
			{
				$offset = $chunks[1]; //Preg offset (substr)
				$plain_text = substr($text, 0, $offset);
				$stack[] = $plain_text; //Text before the tag
			}
			$stack[] = $chunks[0]; //The actual tag
			$text = substr($text, (strlen($chunks[0])+$offset)); //Drop chunk off the string since already processed
			return $this->tokenize($tag, $text, $stack, 1); //Recurse
		}
		else
		{
			$stack[] = $text; //No match, nothing left to do
			return $stack;
		}
		
	}
	
	public function parseQuotes($source='')
	{
		if (empty($source)) $source = $this->source;
		$this->tokens = $this->tokenize('quote', $source);
		$opened = 0;
		$ret = '';
		foreach ($this->tokens as $tok)
		{
			if (preg_match('@'.$this->tags['quote'].'@is', $tok, $matches))
			{
				$info = 'Quote';
				if (!empty($matches[1])) $info = $matches[1].' wrote';
				$ret .= '<div style="border: 1px solid #AAAAAA; padding: 4px; margin: 4px;">
				<div style="font-weight: bold;">'.$info.':</div>';
			}
			elseif (preg_match('@\[/quote\]@is', $tok, $matches))
			{
				$ret .= '</div>';
			}
			else
			{
				$ret .= $tok;
			}
		}
		$this->output = $ret;
		return $this->output;
	}
	
	public function dumpTokens()
	{
		echo '<pre>'.print_r($this->tokens, 1).'</pre>';
	}
	
	private function getOutput()
	{
		return $this->output;
	}
	
	public function fetchResult()
	{
		return $this->getOutput();
	}

}

$text = <<<EOD
Just a test and a [quote]here[/quote]

This should be nested

[quote="foo"]
Look at this [quote]here[/quote] ok?
[/quote]

and end here
EOD;

$bb = new BBCode($text);
$bb->parseQuotes();
$bb->dumpTokens();
echo $bb->fetchResult();

?>

Posted: Sun Jan 22, 2006 1:43 pm
by Chris Corbyn