Skip to content

Commit 35fbd22

Browse files
authored
Merge pull request #39 from bkraul/feat-newparser
New version 2.1.0
2 parents c8c20fb + 2a805f5 commit 35fbd22

20 files changed

+3727
-1864
lines changed

BBCodePlus/BBCodePlus.php

Lines changed: 430 additions & 649 deletions
Large diffs are not rendered by default.

BBCodePlus/core/BBCodeParser.php

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
<?php
2+
3+
namespace Genert\BBCode\Parser;
4+
5+
final class BBCodeParser extends Parser
6+
{
7+
protected $parsers = [
8+
'h1' => [
9+
'pattern' => '/\[h1\](.*?)\[\/h1\]/s',
10+
'replace' => '<h1>$1</h1>',
11+
'content' => '$1'
12+
],
13+
'h2' => [
14+
'pattern' => '/\[h2\](.*?)\[\/h2\]/s',
15+
'replace' => '<h2>$1</h2>',
16+
'content' => '$1'
17+
],
18+
'h3' => [
19+
'pattern' => '/\[h3\](.*?)\[\/h3\]/s',
20+
'replace' => '<h3>$1</h3>',
21+
'content' => '$1'
22+
],
23+
'h4' => [
24+
'pattern' => '/\[h4\](.*?)\[\/h4\]/s',
25+
'replace' => '<h4>$1</h4>',
26+
'content' => '$1'
27+
],
28+
'h5' => [
29+
'pattern' => '/\[h5\](.*?)\[\/h5\]/s',
30+
'replace' => '<h5>$1</h5>',
31+
'content' => '$1'
32+
],
33+
'h6' => [
34+
'pattern' => '/\[h6\](.*?)\[\/h6\]/s',
35+
'replace' => '<h6>$1</h6>',
36+
'content' => '$1'
37+
],
38+
'bold' => [
39+
'pattern' => '/\[b\](.*?)\[\/b\]/s',
40+
'replace' => '<b>$1</b>',
41+
'content' => '$1'
42+
],
43+
'italic' => [
44+
'pattern' => '/\[i\](.*?)\[\/i\]/s',
45+
'replace' => '<i>$1</i>',
46+
'content' => '$1'
47+
],
48+
'underline' => [
49+
'pattern' => '/\[u\](.*?)\[\/u\]/s',
50+
'replace' => '<u>$1</u>',
51+
'content' => '$1'
52+
],
53+
'strikethrough' => [
54+
'pattern' => '/\[s\](.*?)\[\/s\]/s',
55+
'replace' => '<s>$1</s>',
56+
'content' => '$1'
57+
],
58+
'quote' => [
59+
'pattern' => '/\[quote\](.*?)\[\/quote\]/s',
60+
'replace' => '<blockquote>$1</blockquote>',
61+
'content' => '$1'
62+
],
63+
'link' => [
64+
'pattern' => '/\[url\](.*?)\[\/url\]/s',
65+
'replace' => '<a href="$1">$1</a>',
66+
'content' => '$1'
67+
],
68+
'namedlink' => [
69+
'pattern' => '/\[url\=(.*?)\](.*?)\[\/url\]/s',
70+
'replace' => '<a href="$1">$2</a>',
71+
'content' => '$2'
72+
],
73+
'image' => [
74+
'pattern' => '/\[img\](.*?)\[\/img\]/s',
75+
'replace' => '<img src="$1">',
76+
'content' => '$1'
77+
],
78+
'orderedlistnumerical' => [
79+
'pattern' => '/\[list=1\](.*?)\[\/list\]/s',
80+
'replace' => '<ol>$1</ol>',
81+
'content' => '$1'
82+
],
83+
'orderedlistalpha' => [
84+
'pattern' => '/\[list=a\](.*?)\[\/list\]/s',
85+
'replace' => '<ol type="a">$1</ol>',
86+
'content' => '$1'
87+
],
88+
'unorderedlist' => [
89+
'pattern' => '/\[list\](.*?)\[\/list\]/s',
90+
'replace' => '<ul>$1</ul>',
91+
'content' => '$1'
92+
],
93+
'listitem' => [
94+
'pattern' => '/\[\*\](.*)/',
95+
'replace' => '<li>$1</li>',
96+
'content' => '$1'
97+
],
98+
'code' => [
99+
'pattern' => '/\[code\](.*?)\[\/code\]/s',
100+
'replace' => '<code>$1</code>',
101+
'content' => '$1'
102+
],
103+
'youtube' => [
104+
'pattern' => '/\[youtube\](.*?)\[\/youtube\]/s',
105+
'replace' => '<iframe width="560" height="315" src="//www.youtube-nocookie.com/embed/$1" frameborder="0" allowfullscreen></iframe>',
106+
'content' => '$1'
107+
],
108+
'sub' => [
109+
'pattern' => '/\[sub\](.*?)\[\/sub\]/s',
110+
'replace' => '<sub>$1</sub>',
111+
'content' => '$1'
112+
],
113+
'sup' => [
114+
'pattern' => '/\[sup\](.*?)\[\/sup\]/s',
115+
'replace' => '<sup>$1</sup>',
116+
'content' => '$1'
117+
],
118+
'small' => [
119+
'pattern' => '/\[small\](.*?)\[\/small\]/s',
120+
'replace' => '<small>$1</small>',
121+
'content' => '$1'
122+
],
123+
'table' => [
124+
'pattern' => '/\[table\](.*?)\[\/table\]/s',
125+
'replace' => '<table>$1</table>',
126+
'content' => '$1',
127+
],
128+
'table-row' => [
129+
'pattern' => '/\[tr\](.*?)\[\/tr\]/s',
130+
'replace' => '<tr>$1</tr>',
131+
'content' => '$1',
132+
],
133+
'table-data' => [
134+
'pattern' => '/\[td\](.*?)\[\/td\]/s',
135+
'replace' => '<td>$1</td>',
136+
'content' => '$1',
137+
],
138+
];
139+
140+
public function stripTags(string $source): string
141+
{
142+
foreach ($this->parsers as $name => $parser) {
143+
$source = $this->searchAndReplace($parser['pattern'] . 'i', $parser['content'], $source);
144+
}
145+
146+
return $source;
147+
}
148+
149+
public function parse(string $source, $caseInsensitive = null): string
150+
{
151+
$caseInsensitive = $caseInsensitive === self::CASE_INSENSITIVE ? true : false;
152+
153+
foreach ($this->parsers as $name => $parser) {
154+
$pattern = ($caseInsensitive) ? $parser['pattern'] . 'i' : $parser['pattern'];
155+
156+
$source = $this->searchAndReplace($pattern, $parser['replace'], $source);
157+
}
158+
159+
return $source;
160+
}
161+
}

BBCodePlus/core/HTMLParser.php

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
<?php
2+
3+
namespace Genert\BBCode\Parser;
4+
5+
final class HTMLParser extends Parser
6+
{
7+
protected $parsers = [
8+
'h1' => [
9+
'pattern' => '/<h1>(.*?)<\/h1>/s',
10+
'replace' => '[h1]$1[/h1]',
11+
'content' => '$1'
12+
],
13+
'h2' => [
14+
'pattern' => '/<h2>(.*?)<\/h2>/s',
15+
'replace' => '[h2]$1[/h2]',
16+
'content' => '$1'
17+
],
18+
'h3' => [
19+
'pattern' => '/<h3>(.*?)<\/h3>/s',
20+
'replace' => '[h3]$1[/h3]',
21+
'content' => '$1'
22+
],
23+
'h4' => [
24+
'pattern' => '/<h4>(.*?)<\/h4>/s',
25+
'replace' => '[h4]$1[/h4]',
26+
'content' => '$1'
27+
],
28+
'h5' => [
29+
'pattern' => '/<h5>(.*?)<\/h5>/s',
30+
'replace' => '[h5]$1[/h5]',
31+
'content' => '$1'
32+
],
33+
'h6' => [
34+
'pattern' => '/<h6>(.*?)<\/h6>/s',
35+
'replace' => '[h6]$1[/h6]',
36+
'content' => '$1'
37+
],
38+
'bold' => [
39+
'pattern' => '/<b>(.*?)<\/b>/s',
40+
'replace' => '[b]$1[/b]',
41+
'content' => '$1',
42+
],
43+
'strong' => [
44+
'pattern' => '/<strong>(.*?)<\/strong>/s',
45+
'replace' => '[b]$1[/b]',
46+
'content' => '$1',
47+
],
48+
'italic' => [
49+
'pattern' => '/<i>(.*?)<\/i>/s',
50+
'replace' => '[i]$1[/i]',
51+
'content' => '$1'
52+
],
53+
'em' => [
54+
'pattern' => '/<em>(.*?)<\/em>/s',
55+
'replace' => '[i]$1[/i]',
56+
'content' => '$1'
57+
],
58+
'underline' => [
59+
'pattern' => '/<u>(.*?)<\/u>/s',
60+
'replace' => '[u]$1[/u]',
61+
'content' => '$1',
62+
],
63+
'strikethrough' => [
64+
'pattern' => '/<s>(.*?)<\/s>/s',
65+
'replace' => '[s]$1[/s]',
66+
'content' => '$1',
67+
],
68+
'del' => [
69+
'pattern' => '/<del>(.*?)<\/del>/s',
70+
'replace' => '[s]$1[/s]',
71+
'content' => '$1',
72+
],
73+
'code' => [
74+
'pattern' => '/<code>(.*?)<\/code>/s',
75+
'replace' => '[code]$1[/code]',
76+
'content' => '$1'
77+
],
78+
'orderedlistnumerical' => [
79+
'pattern' => '/<ol>(.*?)<\/ol>/s',
80+
'replace' => '[list=1]$1[/list]',
81+
'content' => '$1'
82+
],
83+
'unorderedlist' => [
84+
'pattern' => '/<ul>(.*?)<\/ul>/s',
85+
'replace' => '[list]$1[/list]',
86+
'content' => '$1'
87+
],
88+
'listitem' => [
89+
'pattern' => '/<li>(.*?)<\/li>/s',
90+
'replace' => '[*]$1',
91+
'content' => '$1'
92+
],
93+
'link' => [
94+
'pattern' => '/<a href="(.*?)">(.*?)<\/a>/s',
95+
'replace' => '[url=$1]$2[/url]',
96+
'content' => '$1'
97+
],
98+
'quote' => [
99+
'pattern' => '/<blockquote>(.*?)<\/blockquote>/s',
100+
'replace' => '[quote]$1[/quote]',
101+
'content' => '$1'
102+
],
103+
'image' => [
104+
'pattern' => '/<img src="(.*?)">/s',
105+
'replace' => '[img]$1[/img]',
106+
'content' => '$1'
107+
],
108+
'youtube' => [
109+
'pattern' => '/<iframe width="560" height="315" src="\/\/www\.youtube\.com\/embed\/(.*?)" frameborder="0" allowfullscreen><\/iframe>/s',
110+
'replace' => '[youtube]$1[/youtube]',
111+
'content' => '$1'
112+
],
113+
'linebreak' => [
114+
'pattern' => '/<br\s*\/?>/',
115+
'replace' => '/\r\n/',
116+
'content' => '',
117+
],
118+
'sub' => [
119+
'pattern' => '/<sub>(.*?)<\/sub>/s',
120+
'replace' => '[sub]$1[/sub]',
121+
'content' => '$1'
122+
],
123+
'sup' => [
124+
'pattern' => '/<sup>(.*?)<\/sup>/s',
125+
'replace' => '[sup]$1[/sup]',
126+
'content' => '$1'
127+
],
128+
'small' => [
129+
'pattern' => '/<small>(.*?)<\/small>/s',
130+
'replace' => '[small]$1[/small]',
131+
'content' => '$1',
132+
],
133+
'table' => [
134+
'pattern' => '/<table>(.*?)<\/table>/s',
135+
'replace' => '[table]$1[/table]',
136+
'content' => '$1',
137+
],
138+
'table-row' => [
139+
'pattern' => '/<tr>(.*?)<\/tr>/s',
140+
'replace' => '[tr]$1[/tr]',
141+
'content' => '$1',
142+
],
143+
'table-data' => [
144+
'pattern' => '/<td>(.*?)<\/td>/s',
145+
'replace' => '[td]$1[/td]',
146+
'content' => '$1',
147+
],
148+
];
149+
150+
public function parse(string $source): string
151+
{
152+
foreach ($this->parsers as $name => $parser) {
153+
$source = $this->searchAndReplace($parser['pattern'], $parser['replace'], $source);
154+
}
155+
156+
return $source;
157+
}
158+
}

BBCodePlus/core/Parser.php

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
<?php
2+
3+
namespace Genert\BBCode\Parser;
4+
5+
class Parser
6+
{
7+
/**
8+
* Static case insensitive flag to enable
9+
* case insensitivity when parsing BBCode.
10+
*/
11+
const CASE_INSENSITIVE = 0;
12+
13+
protected $parsers = [];
14+
15+
protected function searchAndReplace(string $pattern, string $replace, string $source): string
16+
{
17+
while (preg_match($pattern, $source)) {
18+
$source = preg_replace($pattern, $replace, $source);
19+
}
20+
21+
return $source;
22+
}
23+
24+
public function only($only = null)
25+
{
26+
$only = is_array($only) ? $only : func_get_args();
27+
28+
$this->parsers = array_intersect_key($this->parsers, array_flip((array) $only));
29+
30+
return $this;
31+
}
32+
33+
public function except($except = null)
34+
{
35+
$except = is_array($except) ? $except : func_get_args();
36+
37+
$this->parsers = array_diff_key($this->parsers, array_flip((array) $except));
38+
39+
return $this;
40+
}
41+
42+
public function addParser(string $name, string $pattern, string $replace, string $content)
43+
{
44+
$this->parsers = array_merge($this->parsers, [
45+
$name => [
46+
'pattern' => $pattern,
47+
'replace' => $replace,
48+
'content' => $content,
49+
],
50+
]);
51+
}
52+
}

0 commit comments

Comments
 (0)