undef$/;$_=<>;s/\[code]((?:(?R)|.)*?)\[\/code]/push@a,$1;"\0"/geis;1while s{\[(b|i|u|img|url|color|size|quote)(?:=([^]]+))?](.*?)\[/\1]}{($n,$x,$y)=(lc$1,$2,$3);$n=~/^u/?$n=~/l/?"<a href=\"".($x||$y)."\">$y</a>":"<u>$y</u>":$n=~/^i/?$n=~/m/?"<img src=\"$y\">":"<em>$y</em>":$n=~/^b/?"<strong>$y</strong>":$n=~/^q/?"<blockquote>".($x?"<cite>$x</cite>":"")."$y</blockquote>":"<span style=\"".($n=~/c/?"color":"font-size").":$x\">$y</span>"}gie;s/\0/"<code>".shift(@a)."<\/code>"/ge;print
Try it online!
Detailed explaination
undef$/;$_=<>;
Undefines the line separator so $_=<>; reads the entire input (newlines and all) into the default variable $_ at once.
s/\[code]((?:(?R)|.)*?)\[\/code]/push@a,$1;"\0"/geis;
Matches a [code] block and substitutes its contents with a null byte \0, saving them in the array @a for later.
1 while s{\[(b|i|u|img|url|color|size|quote)(?:=([^]]+))?](.*?)\[/\1]}{
($n,$x,$y)=(lc$1,$2,$3);
$n=~/^u/?$n=~/l/?"<a href=\"".($x||$y)."\">$y</a>":"<u>$y</u>":
$n=~/^i/?$n=~/m/?"<img src=\"$y\">":"<em>$y</em>":
$n=~/^b/?"<strong>$y</strong>":
$n=~/^q/?"<blockquote>".($x?"<cite>$x</cite>":"")."$y</blockquote>":
"<span style=\"".($n=~/c/?"color":"font-size").":$x\">$y</span>"
}gie;
s{...}g replaces all matching tags in the string. The while loop handles nested tags.
$n is the tag name
$x are the tag attributes if present
$y is what's within the tag
Inside the loop, a set of if/else replace the appropriate tags.
- Starts with
u? -> u or url
- Starts with
i? -> img or i
- Starts with
b? -> b.
- Starts with
q? quote (adds <cite>...</cite> only if an author $x was defined)
- Else: It must be
color or size. We can merges these because they both output <span style="..."> by checking if the name contains c to decide between color: or font-size:.
s/\0/"<code>".shift(@a)."<\/code>"/ge;
print
s/\0/.../ge finds every null byte placeholder created in the beginning and replaces it (FIFO) shift(@a) with the array contents.