#! /usr/local/bin/perl
use strict;
use warnings;
# $i: italic
# $s: shadowed
# $w: wide spacing
# $n: narrow spacing
# $m: normal setting
# $g: default color
# $t: changes the text to capitals
# $z: reset all
# $$: to write a "$"
my %classes = (
i => 'italics',
s => 'shadowed',
w => 'wide',
n => 'narrow',
m => 'normal',
);
my %testcases = (
'$iMy$z$w$f00Nickname' =>
'MyNickname',
'$s$5aaD$ddfia$5aaD$ddfe$5cc§' =>
'DiaDe§',
'$iT$sh$wi$ns is $m$444silly$z $tsmall stuff$z and BIG STUFF' =>
'This is silly SMALL STUFF and BIG STUFF',
'$wWIDE$nNARROW$mnormal' =>
'WIDENARROWnormal',
'$ta$$zas$zdf' => 'A$ZASdf',
'$tasdf' => 'ASDF',
'$s$02fCamster $0bfb$018s$0bfc' =>
'Camster bsc',
'$00fS$fffa$00fo$fffr$00fs$fffa $00fB$fffs$00fc' =>
'Saorsa Bsc',
'$i$s$f06Jasmine' =>
'Jasmine',
'$i$s$f90Ario$06fñ$f90e $s$ff0 $s$fob' =>
'Arioñe ob',
'$s$i$00aM$0afarcus b$00as$0afc' =>
'Marcus bsc',
'$i$fffArthur $s$00fBSC $f00N$fffE$00fD ' =>
'Arthur BSC NED ',
'$w$s$fffSalt$i$m$00fheart' =>
'Saltheart',
'sonny $s$36FBSC' =>
'sonny BSC',
'$s$5aaD$ddfia$5aaD$ddfe$5cc§' =>
'DiaDe§',
'$ff0hula' => 'hula',
'$s$i$f00Ma$fffnta $00fGB ' =>
'Manta GB ',
'$i$s$t $fffPolar Bear' =>
' POLAR BEAR',
'$w$325TULEBA$500(bsc)' =>
'TULEBA(bsc)',
'$s$i$fffAdoo$015nis $i$0BFb$018s$0BFc' =>
'Adoonis bsc',
);
foreach ( keys %testcases ) {
my $string = $_;
my @stack; # a stack of open tags
my $italics = 0; # text is italics
my $shadowed = 0; # text is shadowed
my $width = 'm'; # text is wide (w) or narrow (n) or normal (m)
my $color = 0; # text is colored ($rgb)
my $capitals = 0; # text is capitalized
while ( $string =~ m/(\$[iswnmgtz\$]|\$[0-9a-f]{3,3})([^\$]*)/ig ) {
my $tag = $1;
my $text = $2;
my $len = length($tag) + length($text);
my $pos = pos($string);
my $replacement = "";
my $c = lc( substr( $1, 1, 1 ) );
if ( $c eq 'i' ) { # following text is italicized
unless ($italics) {
$italics = 1;
my $open_tag = '';
push( @stack, $open_tag );
$replacement = $open_tag;
}
} elsif ( $c eq 's' ) { # following text is shadowed
unless ($shadowed) {
my $open_tag = '';
$replacement = $open_tag;
push( @stack, $open_tag );
$shadowed = 1;
}
} elsif ( $c eq 'w' ) { # following text is wide
unless ( $width eq 'w' ) {
my $open_tag = '';
$replacement = clear_width( \@stack ) if ( $width ne 'm' );
$replacement .= $open_tag;
push( @stack, $open_tag );
$width = 'w';
}
} elsif ( $c eq 'n' ) { # following text is narrow
unless ( $width eq 'n' ) {
my $open_tag = '';
$replacement = clear_width( \@stack ) if ( $width ne 'm' );
$replacement .= $open_tag;
push( @stack, $open_tag );
$width = 'n';
}
} elsif ( $c eq 'm' ) { # following text is normal width
unless ( $width eq 'm' ) {
$replacement = clear_width( \@stack );
$width = 'm';
}
} elsif ( $c eq 'g' ) { # following text is default color
if ($color) {
$replacement = clear_color( \@stack );
$color = '';
}
} elsif ( $c eq 't' ) { # following text is capitalized
$capitals = 1;
} elsif ( $c eq 'z' ) { # following text is without any applied style
$replacement = clear_all( \@stack );
$italics = 0;
$shadowed = 0;
$width = 'm';
$color = '';
$capitals = 0;
} elsif ( $c eq '$' ) { # a '$'
$replacement = '$';
} elsif ( $tag =~ m/\$[0-9a-f]{3,3}/i ) { # following text is colored
unless ( $color eq $tag ) {
my ( $x, $r, $g, $b ) = split( //, $tag );
my $open_tag = lc("");
$replacement = clear_color( \@stack );
$replacement .= $open_tag;
push( @stack, $open_tag );
$color = $tag;
}
} else { # If we don't recognize it leave it unchanged
warn "unknown tag $tag";
$replacement = substr( $tag, 0, 2 );
}
$replacement .= $capitals ? uc($text) : $text;
substr( $string, $pos - $len, $len, $replacement );
pos($string) = $pos - $len + length($replacement);
}
$string .= clear_all( \@stack );
$string = tidy($string);
if ( $string eq $testcases{$_} ) {
print "\n\nOk '$_' =>\n '$string'\n";
} else {
print "\n\nNot Ok '$_' =>\n '$string' expecting:\n '$testcases{$_}'\n";
}
}
exit(0);
# clear the stack, closing all tags
sub clear_all {
my $stack = shift;
my $text;
while ( my $tag = pop( @{$stack} ) ) {
if ( $tag =~ m/^<(\S+)/ ) {
$text .= "$1>";
} else {
die "$tag: invalid tag format";
}
}
return ($text);
}
# clear prior color
# do nothing if there is no color tag open
# close all tags nested within current color tag
# close color tag
# re-open all nested tags
sub clear_color {
my $stack = shift;
return ("") unless ( grep { $_ =~ m/^/ } @{$stack} );
my $text;
my @reopen;
while ( my $tag = pop( @{$stack} ) ) {
if ( $tag eq '' or $tag eq '' )
{
$text .= '';
last; # we can only have one width tag in the stack
} elsif ( $tag =~ m/^<(\S+)/ ) {
push( @reopen, $tag );
$text .= "$1>";
} else {
die "$tag: invalid tag format";
}
}
while ( my $tag = pop(@reopen) ) {
push( @{$stack}, $tag );
$text .= $tag;
}
return ($text);
}
# Remove all tag pairs without content:
sub tidy {
my $string = shift;
while ( $string =~ s!<(\S+)[^>]*>\1>!! ) { }
return ($string);
}