Skip to content

Instantly share code, notes, and snippets.

@RogerDodger
Last active December 8, 2020 21:05
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save RogerDodger/4405595 to your computer and use it in GitHub Desktop.
Save RogerDodger/4405595 to your computer and use it in GitHub Desktop.
Converts Markdown to BBCode
#!/usr/bin/env perl
use strict;
use warnings;
use 5.01;
use Text::Markdown;
use Encode;
use HTML::Entities;
use Getopt::Long;
# Ensure proper encoding of IO
use open qw/:std :utf8/;
binmode(STDIN, ':utf8');
binmode(STDOUT, ':utf8');
binmode(STDERR, ':utf8');
# Get options
my $opt = { code => 0, lists => 0, smartypants => 1 };
GetOptions($opt, qw/code lists smartypants!/);
# Read input
my $in;
my $fn = shift;
if (defined $fn && -r $fn) {
open READ, '<', $fn;
$in = eval { local $/; <READ> };
close READ;
}
else {
$in = eval { local $/; <STDIN> };
}
# Profit
print md2bbc($in, $opt);
sub md2bbc {
local $_ = shift or return '';
my $opt = shift;
# Override the Text::Markdown method that handles lists to do
# nothing if we don't have BBCode lists supported
eval {
no warnings 'redefine';
sub Text::Markdown::_DoLists {
my( $self, $text ) = @_;
return $text;
}
} unless $opt->{lists};
$_ = Text::Markdown->new->markdown($_);
# Smartypants operates first so that attributes (e.g., URLs) don't get converted
if ($opt->{smartypants}) {
if (eval { require Text::SmartyPants }) {
$_ = Text::SmartyPants::process($_, 2);
}
elsif (eval { require Text::Typography }) {
$_ = Text::Typography::typography($_, 2);
}
}
# Simple elements
my %html2bb = (
strong => 'b',
em => 'i',
blockquote => 'quote',
hr => 'hr',
);
while (my($html, $bb) = each %html2bb) {
s{<(/|)$html[^>]*>}{[$1$bb]}g;
}
# Convert links
s{<a
[^>]*? # random attributes we don't care about
href="(.+?)" # target
[^>]*? # more random attributes we don't care about
>
(.+?) # text
</a>
}{[url="$1"]$2\[/url]}xg;
# Undo paragraphs elements
s{</?p>}{}g;
# Undo code elemeents
if ($opt->{code}) {
s{<pre><code>} {[code]}g;
s{</code></pre>} {[/code]}g;
}
else {
s{<pre><code>\s*} {}g;
s{\s*</code></pre>} {}g;
}
# Convert list elements
if ($opt->{lists}) {
s{<ul>} {[list]}g;
s{<ol>} {[list=1]}g;
s{</[uo]l>} {[/list]}g;
s{<li>} {[*]}g;
s{</li>} {}g;
}
# Decode HTML entities
return decode_entities $_;
}
@tangentsoft
Copy link

Hi! Thanks for the script. It worked just fine on the first sample I sent it, with one exception: many BBCode implementations won't cope with <h1> and such. May I suggest that you emit [font size=7] for the top-level heading down to size 3 for a fourth-level heading? Size 2 is usually the size of normal paragraph text, and size 1 is usually smaller than that, for footnotes and such.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment