#!/usr/bin/perl # Převede zdroják Media Wiki (např. wiki StatMT CLIP UMIACS) do Doku Wiki (např. wiki ÚFAL MFF UK). # (c) 2008 Dan Zeman <zeman@ufal.mff.cuni.cz> # Licence: GNU GPL use utf8; use open ":utf8"; binmode(STDIN, ":utf8"); binmode(STDOUT, ":utf8"); binmode(STDERR, ":utf8"); # Načíst zdroják Media Wiki. while(<>) { $wiki .= $_; } # Převést konstrukce Media Wiki do pseudo-HTML. $wiki =~ s/&/&/sg; $wiki =~ s/</</sg; $wiki =~ s/>/>/sg; $wiki =~ s/\[\[(.*?)\|(.*?)\]\]/<a href='$1'>$2<\/a>/sg; $wiki =~ s/\[(http.*?) (.*?)\]/<a href='$1'>$2<\/a>/sg; $wiki =~ s/^====\s*(.*?)\s*====$/<h4>$1<\/h4>/mg; $wiki =~ s/^===\s*(.*?)\s*===$/<h3>$1<\/h3>/mg; $wiki =~ s/^==\s*(.*?)\s*==$/<h2>$1<\/h2>/mg; $wiki =~ s/^=\s*(.*?)\s*=$/<h1>$1<\/h1>/mg; $wiki =~ s/'''(.*?)'''/<b>$1<\/b>/sg; $wiki =~ s/''(.*?)''/<i>$1<\/i>/sg; $wiki =~ s/<tt>(.*?)<\/tt>/<tt>$1<\/tt>/sg; $wiki =~ s/<sub>(.*?)<\/sub>/<sub>$1<\/sub>/sg; $wiki =~ s/<sup>(.*?)<\/sup>/<sup>$1<\/sup>/sg; $wiki =~ s/<pre>(.*?)<\/pre>/<pre>$1<\/pre>/sg; $wiki =~ s/<span (.*?)>(.*?)<\/span>/<span $1>$2<\/span>/sg; $wiki =~ s/^\*\*\*\*\s*/<uli4>/mg; $wiki =~ s/^\*\*\*\s*/<uli3>/mg; $wiki =~ s/^\*\*\s*/<uli2>/mg; $wiki =~ s/^\*\s*/<uli1>/mg; # Tabulky mají složitější syntax, takže si nevystačíme pouze s regulárními výrazy. while($wiki =~ s/(\{\|.*?\|\})/<_table_being_read_>/s) { my $tabulka = $1; push(@tabulky, dekodovat_tabulku($tabulka)); $wiki =~ s/<_table_being_read_>/<table$#tabulky>/s; } # Převést pseudo-HTML na konstrukce Doku Wiki. $wiki =~ s/<a href='(.*?)'>(.*?)<\/a>/[[$1|$2]]/sg; $wiki =~ s/<h1>(.*?)<\/h1>/======$1======/mg; $wiki =~ s/<h2>(.*?)<\/h2>/=====$1=====/mg; $wiki =~ s/<h3>(.*?)<\/h3>/====$1====/mg; $wiki =~ s/<h4>(.*?)<\/h4>/===$1===/mg; $wiki =~ s/<b>(.*?)<\/b>/**$1**/sg; $wiki =~ s/<i>(.*?)<\/i>/\/\/$1\/\//sg; $wiki =~ s/<tt>(.*?)<\/tt>/''$1''/sg; $wiki =~ s/<pre>(.*?)<\/pre>/<code>$1<\/code>/sg; $wiki =~ s/(<span .*?>.*?<\/span>)/<html>$1<\/html>/sg; $wiki =~ s/<uli1>/ * /mg; $wiki =~ s/<uli2>/ * /mg; $wiki =~ s/<uli3>/ * /mg; $wiki =~ s/<uli4>/ * /mg; # Tabulky mají složitější syntax, takže si nevystačíme pouze s regulárními výrazy. while($wiki =~ s/<table(\d+)>/<_table_being_written_>/s) { my $index = $1; my $tabulka = zakodovat_tabulku($tabulky[$index]); $wiki =~ s/<_table_being_written_>/$tabulka/s; } $wiki =~ s/>/>/sg; $wiki =~ s/</</sg; $wiki =~ s/&/&/sg; # Dokuwiki neumí většinu entit HTML, proto dekódovat i ty < a >, které už byly v kódu MediaWiki. $wiki =~ s/>/>/sg; $wiki =~ s/</</sg; # Vypsat převedený zdroják na standardní výstup. print($wiki); #------------------------------------------------------------------------------ # Rozebere tabulku v syntaxi Media Wiki a uloží ji jako pole buněk. #------------------------------------------------------------------------------ sub dekodovat_tabulku { my $tabulka = shift; # Rozsekat kód tabulky na řádky. my @radky_kodu = split(/\r?\n/, $tabulka); # Projít řádky kódu, přečíst parametry celé tabulky a rozdělit kód podle řádků tabulky (což není totéž jako řádky kódu). my $atributy_tabulky; my @radky_tabulky; foreach my $radek (@radky_kodu) { if($radek =~ m/^\{\|(.*)/) { $atributy_tabulky = $1; } elsif($radek =~ m/^\|([^-\|\}].*)/) { # Umazat úvodní svislítko. $radek = $1; $radek =~ s/^\s+//; $radek =~ s/\s+$//; my @bunky = split(/\s*\|\|\s*/, $radek); # Projít buňky a oddělit atributy od obsahu. foreach my $bunka (@bunky) { my %bunka; if($bunka =~ m/^(.*?)\|(.*)$/) { my $atributy = $1; $bunka{obsah} = $2; my @atributy = split(/\s+/, $atributy); foreach my $atribut (@atributy) { # $atribut nemůže obsahovat mezery, protože na mezerách jsme odsekávali atributy od sebe. # Nemusíme se proto starat o mezery v následujícím regulárním výrazu. if($atribut =~ m/^(.+?)=(.*)$/) { $bunka{$1} = $2; } else { $bunka{$atribut}++; } } } else { $bunka{obsah} = $bunka; } # V původním poli buněk nahradit řetězec odkazem na hash. $bunka = \%bunka; } push(@radky_tabulky, \@bunky); } } # Vytvořit hash z atributů a matice buněk a vrátit odkaz na něj. my %tabulka = ( 'atributy' => $atributy_tabulky, 'radky' => \@radky_tabulky ); return \%tabulka; } #------------------------------------------------------------------------------ # Vypíše tabulku v syntaxi Doku Wiki. #------------------------------------------------------------------------------ sub zakodovat_tabulku { my $tabulka = shift; # odkaz na hash s atributy a maticí buněk my $kod; # Dokuwiki neumí rowspany. Projít tabulku a vložit místo nich prázdné buňky. for(my $i = 0; $i<=$#{$tabulka->{radky}}; $i++) { for(my $j = 0; $j<=$#{$tabulka->{radky}[$i]}; $j++) { if(exists($tabulka->{radky}[$i][$j]{rowspan})) { # Na každý následující řádek v rowspanu přidat do příslušného místa prázdnou buňku. for(my $k = $i+1; $k<=$i+$tabulka->{radky}[$i][$j]{rowspan}-1; $k++) { # Pokud má aktuální buňka také colspan, nezapomenout ho okopírovat i do vkládané prázdné buňky. my %bunka = ('obsah' => ''); if(exists($tabulka->{radky}[$i][$j]{colspan})) { $bunka{colspan} = $tabulka->{radky}[$i][$j]{colspan}; } splice(@{$tabulka->{radky}[$k]}, $j, 0, \%bunka); } } } } # Dokuwiki špatně snáší, když všechny řádky tabulky nemají stejný počet buněk. # Zjistit počet buněk v nejdelším řádku tabulky. my $max_delka_radku = 0; foreach my $radek (@{$tabulka->{radky}}) { my $delka_radku = 0; foreach my $bunka (@{$radek}) { if(exists($bunka->{colspan})) { $delka_radku += $bunka->{colspan}; } else { $delka_radku++; } } $max_delka_radku = $delka_radku if($delka_radku>$max_delka_radku); } # Doplnit řádky prázdnými buňkami na maximální počet. foreach my $radek (@{$tabulka->{radky}}) { my $delka_radku = 0; foreach my $bunka (@{$radek}) { if(exists($bunka->{colspan})) { $delka_radku += $bunka->{colspan}; } else { $delka_radku++; } } # Vlastní doplňování začíná tady. for(my $i = $delka_radku+1; $i<=$max_delka_radku; $i++) { push(@{$radek}, {'obsah' => ''}); } } # Zakódovat tabulku v syntaxi Doku Wiki. foreach my $radek (@{$tabulka->{radky}}) { $kod .= join('', map { my $vysledek = $_->{obsah}; $vysledek =~ s/^\s+//s; $vysledek =~ s/\s+$//s; if($_->{align} eq "center") { $vysledek = " $vysledek "; } elsif($_->{align} eq "left") { $vysledek = " $vysledek "; } elsif($_->{align} eq "right") { $vysledek = " $vysledek "; } else { $vysledek = " $vysledek "; } $vysledek = '|'.$vysledek; for(my $i = 2; $i<=$_->{colspan}; $i++) { $vysledek .= '|'; } $vysledek; } (@{$radek}))."|\n"; } return $kod; }