in reply to Re^2: Game Nicknames to HTML
in thread Game Nicknames to HTML

I have rewritten to avoid nesting of tags. The new version succeeds on all cases except "$i$s$f90Ario$06fñ$f90e $s$ff0 $s$fob" which has an invalid "$fob" at the end. For the moment it leaves the $f unchanged but maybe it should be removed, or maybe only the $ should be removed.

This version of the script seems to work. I would welcome any suggestions for improvement. Are there modules I should consider? Better ways to test??

#! /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' => '<span class="italics">My</span><span class="wide"><font color="#ff000 +0">Nickname</font></span>', '$s$5aaD$ddfia$5aaD$ddfe$5cc§' => '<span class="shadowed"><font color="#55aaaa">D</font><font color="#dd +ddff">ia</font><font color="#55aaaa">D</font><font color="#ddddff">e< +/font><font color="#55cccc">§</font></span>', '$iT$sh$wi$ns is $m$444silly$z $tsmall stuff$z and BIG STUFF' => '<span class="italics">T<span class="shadowed">h<span class="wide">i</ +span><span class="narrow">s is </span><font color="#444444">silly</fo +nt></span></span> SMALL STUFF and BIG STUFF', '$wWIDE$nNARROW$mnormal' => '<span class="wide">WIDE</span><span class="narrow">NARROW</span +>normal', '$ta$$zas$zdf' => 'A$ZASdf', '$tasdf' => 'ASDF', '$s$02fCamster $0bfb$018s$0bfc' => '<span class="shadowed"><font color="#0022ff">Camster </font><font col +or="#00bbff">b</font><font color="#001188">s</font><font color="#00bb +ff">c</font></span>', '$00fS$fffa$00fo$fffr$00fs$fffa $00fB$fffs$00fc' => '<font color="#0000ff">S</font><font color="#ffffff">a</font><font col +or="#0000ff">o</font><font color="#ffffff">r</font><font color="#0000 +ff">s</font><font color="#ffffff">a </font><font color="#0000ff">B</ +font><font color="#ffffff">s</font><font color="#0000ff">c</font>', '$i$s$f06Jasmine' => '<span class="italics"><span class="shadowed"><font color="#ff0066">Ja +smine</font></span></span>', '$i$s$f90Ario$06fñ$f90e $s$ff0 $s$fob' => '<span class="italics"><span class="shadowed"><font color="#ff9900">Ar +io</font><font color="#0066ff">ñ</font><font color="#ff9900">e </fon +t><font color="#ffff00"> ob', '$s$i$00aM$0afarcus b$00as$0afc' => '<span class="shadowed"><span class="italics"><font color="#0000aa">M< +/font><font color="#00aaff">arcus b</font><font color="#0000aa">s</f +ont><font color="#00aaff">c</font></span></span>', '$i$fffArthur $s$00fBSC $f00N$fffE$00fD ' => '<span class="italics"><font color="#ffffff">Arthur </font><span class +="shadowed"><font color="#0000ff">BSC </font><font color="#ff0000">N< +/font><font color="#ffffff">E</font><font color="#0000ff">D </font></ +span></span>', '$w$s$fffSalt$i$m$00fheart' => '<span class="wide"><span class="shadowed"><font color="#ffffff">Salt< +/font></span></span><span class="shadowed"><span class="italics"><fon +t color="#0000ff">heart</font></span></span>', 'sonny $s$36FBSC' => 'sonny <span class="shadowed"><font color="#3366ff">BSC</font></ +span>', '$s$5aaD$ddfia$5aaD$ddfe$5cc§' => '<span class="shadowed"><font color="#55aaaa">D</font><font color="#dd +ddff">ia</font><font color="#55aaaa">D</font><font color="#ddddff">e< +/font><font color="#55cccc">§</font></span>', '$ff0hula' => '<font color="#ffff00">hula</font>', '$s$i$f00Ma$fffnta $00fGB ' => '<span class="shadowed"><span class="italics"><font color="#ff0000">Ma +</font><font color="#ffffff">nta </font><font color="#0000ff">GB </f +ont></span></span>', '$i$s$t $fffPolar Bear' => '<span class="italics"><span class="shadowed"> <font color="#ffffff">P +OLAR BEAR</font></span></span>', '$w$325TULEBA$500(bsc)' => '<span class="wide"><font color="#332255">TULEBA</font><font color="#5 +50000">(bsc)</font></span>', '$s$i$fffAdoo$015nis $i$0BFb$018s$0BFc' => '<span class="shadowed"><span class="italics"><font color="#ffffff">Ad +oo</font><font color="#001155">nis </font><font color="#00bbff">b</f +ont><font color="#001188">s</font><font color="#00bbff">c</font></spa +n></span>', ); 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 = '<span class="italics">'; push( @stack, $open_tag ); $replacement = $open_tag; } } elsif ( $c eq 's' ) { # following text is shadowed unless ($shadowed) { my $open_tag = '<span class="shadowed">'; $replacement = $open_tag; push( @stack, $open_tag ); $shadowed = 1; } } elsif ( $c eq 'w' ) { # following text is wide unless ( $width eq 'w' ) { my $open_tag = '<span class="wide">'; $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 = '<span class="narrow">'; $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 app +lied 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("<font color=\"#$r$r$g$g$b$b\">"); $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 '$testcase +s{$_}'\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/^<font/ } @{$stack} ); my $text; my @reopen; while ( my $tag = pop( @{$stack} ) ) { if ( $tag =~ m/^<font/ ) { $text .= '</font>'; last; # we can only have one font 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); } # clear prior width # do nothing if there is no width tag open # close all tags nested within current width tag # close width tag # re-open all nested tags sub clear_width { my $stack = shift; return ("") unless ( grep { $_ =~ m/^<span class="(wide|narrow)">/ } @{$stac +k} ); my $text; my @reopen; while ( my $tag = pop( @{$stack} ) ) { if ( $tag eq '<span class="wide">' or $tag eq '<span class="na +rrow">' ) { $text .= '</span>'; 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: <tag></tag> sub tidy { my $string = shift; while ( $string =~ s!<(\S+)[^>]*></\1>!! ) { } return ($string); }

update: adjusted whitespace per Perl::Tidy. Perl::Critic said it was OK ( a pleasant surprise for my first time using it - maybe I do have some good habits...).

Replies are listed 'Best First'.
Re^4: Game Nicknames to HTML
by baltic.sailor (Novice) on Mar 31, 2009 at 08:34 UTC
    Again, thanks a lot for the work you are doing here!!

    I will do some further testing next weekend and tell you what I found out. It was not my intention to create so much work. Initially I was just looking for a module to do this job.

    I totally appreciate your work on this!

    If you want some more input to test with here it is:

    $000bow$f00man$ff042 $00f(ayc200) $000det$i$F00mit$z$s$FF0 f $00fBar$fffbe Bl$f00eue $000 ~TEAM DEMO $00fCricka $ff0VSK-SwedenRace $00fJ$z$fffb$00fa$z$fffr $w$00f01 $00fjl$fffl$foo14 $00fS$fffa$00fo$fffr$00fs$fffa $00fB$fffs$00fc $00Fto$FFFm$F0014 $09fDelphisa $0f0A$ffflar$f00e $i$nSeppia Team $0F0r$0F5a$0FBf$0EFf$08Fa$03F $30F[vska] $0f9morgan $c90goldfinger II ayc700 $f00 VM - ($fffden$f00 259) $f00$sA$0f0r$ffft ( $0f wales$fff) $F00J$F88a$FFFm$FFFp$00ai$009t $F00Jaws$009(AUS10$009) $f00Steel$fffviking$f00(DEN) $ff0hula $i$3f0$sWazari-$00fBSC-$z$i$f00U$fffS$00fA $i$900<-j$fffT$900l-$n<< $i$900<-jTl-<$n$0bfb$018S$0bfc $i$900j$fffT$900l-$n$6cfb$00fS$6cfc $900 Happy Birthday $i$900Sweet emma of new Orleans $i$cc6$sTi'Chon $00fb.$fffw$f00.s $i$fffArthur $s$00fBSC $f00N$fffE$00fD $i$s$0f0Mivla /$z$i$s$f00/ por $i$s$3f3Franco$f00Drao $z$s$fff $I$S$F00Prev$fffeze$F00***$Footur$fffkey*** $i$s$f06Jasmine $i$s$f06Luna $i$s$f80l$59funa$f80s$59fard$f80a$z $i$s$f80Mart$fff ($f00n$fffe$00fd$fff) $i$s$f90Ario$06fñ$f90e $s$ff0 $s$fob $i$s$ff0WabbiT $fffAYC - $f00450 $i$s$fffLuna $i$s$fofLuna $i$s$t $fffPolar Bear $i$w$0f0cocal $n$ff$i_~_ $M$S$i$f00ANTISTENE $00fB.$fffW.$f00S $N$000kiwi_$FFFbardy $n$s$090Magnolia $s $f80Schollie $fff($f00n$fffe$00fd$fff) $s$02fCamster $0bfb$018s$0bfc $s$11aPaolofico $a11yc$s$0f0W$fffL$f00F $i$s$fd0I-Team $s$5aaD$ddfia$5aaD$ddfe$5cc§ $s$888SunnyVale Trailer Park $s$a00Crazycat $s$f01BSC $s$aaaTurebo$z$f81Mc$zQeck$f72($Foon$fffe$00ad$f72) $s$b01Crazycat $s$f01BSC $s$f80Thermic $s$fooCom$fffpul$00fsion - $i$nvsk-$t$f00u$fffs$00fa $s$i$00aM$0afarcus $s$i$00aM$0afarcus b$00as$0afc $s$i$444sun$e22b$444urn $S$i$C11euphoria $000VSK $C11Nordic $s$i$f00Ma$fffnta $00fGB $s$i$f00Ma$fffnta $00fGB $w$s$00cB$w$s$09fS$w$s$00cC $s$i$F90Davarch $s$i$fc0euphoria $000VSK $C11Nordic $s$i$fc0odin $s$i$fffAdoo$015nis $i$0BFb$018s$0BFc $s$i$fffAdoo$018nis $i$0BFB$018S$0BFC $s$i$fffAdoo$018nis $i$n$s$0BFB$018S$0BFC $s$i$fffAdoo$91Fnis $s$w$i$006GRE144$FF3 i-team $W$00cSWE 110 $n$ff0VSK Sweden Race $w$325TULEBA$500(bsc) $w$s$3cfnewworld-bsc $w$s$fffHenry$f00HH $w$s$fffSalt$i$m$00fheart $w$s$i$09fy$05fu$00fg $10fb.$10fw.$10fs $w$s$i$0cfaramis $w$s$i$0cfbre$0afta$09fgn$05fe 3$00f5 b.$fffw.$f00s $w$s$i$0cff$0afr$09f9$05f8$00f5 b.$fffw$f00.s $w$s$i$0cfgil$0afle$09fs 2 b$05fob$00fo b.$fffw.$f00s $w$s$i$0cfsurcouf Vic_Anacortes $m$f00B$fffS$00fC
    Thomas