#! /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 .= ""; } 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 .= ""; } 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+)[^>]*>!! ) { } return ($string); }