Это старая версия документа.
Официальная Wiki Ubuntu сидит на движке MoinMoin, мы же используем DokuWiki. Озадачившись вопросами конвертации синтаксиса нашёл лишь это, что только приблизительно позволяет преобразовать основные конструкции. Поэтому, ради спортивного интереса, набросал скриптик на перле (замените только в нём <!/code> на </code> в одном месте, иначе местный парсер ломается):
#!/usr/bin/perl -w # Usage: ./convert.pl moin_file doku_file [namespace] # namespace - for all links to images ({{namespace:image.png}}) use 5.010; # We need it # ----------------------------------------------------------------------------------------------- # # Convert text file with MoinMoin Wiki syntax to DokuWiki syntax # # by Malamut (malamut@ubuntu.ru) (2009) # # ----------------------------------------------------------------------------------------------- # # Hash for smileys replacement (actual for ubuntu.com wiki) %smileys = ( #moin doku 'X-(' => ':-X', ':D' => ':-D', '<:(' => ':-?', ':o' => ':-O', ':(' => ':-(', ':)' => ':-)', 'B)' => '8-)', ':))' => ':-P', ';)' => ';-)', '/!\\' => ':!:', '<!>' => ':!:', '(!)' => ':!:', ':-?' => ':-P', ':\\' => ':-\\', '>:>' => '^_^', '|)' => ':-|', ':-(' => ':-(', ':-)' => ':-)', 'B-)' => '8-)', ':-))' => ':-P', ';-)' => ';-)', '|-)' => ':-|', '(./)' => 'LOL', '{OK}' => ':!:', '{X}' => ':!:', '{i}' => ':!:', '{1}' => '<1>', '{2}' => '<2>', '{3}' => '<3>', '{*}' => '<ubu>', '{o}' => '<circ>', ); # For links regex sub inv { given ($_[0]) { when ("{") { return "}" } when ("[") { return "]" } } return $_[0]; } # Link sub link_replacement { die "Oops!\n" if @_ != 5; my ($namespace,$br,$target,$text,$params) = @_; # Attachments links if ($target =~ /^(?:(?:attachment|drawing):)(?<att>.+)$/) { (my $att = $+{att}) =~ s{(.+)/}{}; # leave only filename, without namespaces if ($text) { return "{{$namespace:$att|$text}}" } else { return "{{$namespace:$att}}" } } # InterWiki links if ($target =~ m#^(.+?):(?!//)(.+)$#) { # all with : except internet links (containing ://) if ($text) { return "[[$1>$2|$text]]" } else { return "[[$1>$2]]" } } # All other links simply returned in doku format $target =~ s#/#:#g if $target !~ m#://#; # if target not an internet link replace all / to : (for namespaces) if ($text) { return "$br$br$target|$text" . inv($br) x 2 } else { return "$br$br$target" . inv($br) x 2 } } # Block sub block_replacement { for (my $i = 0; $i < @_ && $_[$i] =~ /^\$*$/; $i++ ) { shift @_ } # delete empty lines for (my $i = -1; -$i <= @_ && $_[$i] =~ /^\$*$/; $i-- ) { pop @_ } # delete empty lines if (!@_) { unshift @_, "<code>\n" } elsif ($_[0] =~ /^\s*#!python/) { shift @_; unshift @_, "<code python>\n" } elsif ($_[0] =~ /^\s*#!cplusplus/) { shift @_; unshift @_, "<code cpp>\n" } elsif ($_[0] =~ /^\s*#!java/) { shift @_; unshift @_, "<code java>\n" } elsif ($_[0] =~ /^\s*#!pascal/) { shift @_; unshift @_, "<code pascal>\n" } elsif ($_[0] =~ /^\s*#.+/) { shift @_; unshift @_, "<code>\n" } else { unshift @_, "<code>\n" } push @_, "<!/code>\n"; return @_; } # Table sub table_replacement { @table = @_; for (@table) { s/\|\|(?:\s*(<.+?>))?\s*(.+?)\s*(?=\|\|)/ # delete all whitespaces if ($1) { "||$1$2" } else { "||$2" } /ge; s/((?:\|\|){2,})(.+?)(?=\|\|)/ # move few || to another side of cell and center "|| $2 " . '|' x (length($1) - 2) /ge; # Spanning # TODO # Aligment # TODO #s/\|\|.*?(?:(?:<\(>)|(?:<style="text-align: left">))(?=\|\|)//g; # left #s/<:>//g; # center #s/<\)>//g; # right # Ok, thats all s/\|\|(\s*)(?:<.+?>\s*?)+(.*?)(?=\|\|)/||$1$2/g; # remove all tags, we really don't need it s/\|\|/|/g; # finally replace || to | } # Remove all empty strings for (0..$#table) { if ($table[$_] =~ /^\|+$/) { splice @table, $_, 1 } } return @table; } # Convert moin file (first argument) to doku file (second argument), namespace for attachments is the third argument (default - (.)) sub ConvertMoinToDoku { die "ConvertMoinToDoku: I need 2 or 3 arguments!\n" if (@_ != 2 and @_ != 3); my $moin = shift @_; my $doku = shift @_; my $namespace = shift @_ // '.'; #/#3rd argument or (.) open INFILE, "<", $moin or die "Can't open '$moin' ($!)!\n"; open OUTFILE, ">", $doku or die "Can't open '$doku' ($!)!\n"; my $intend = 0; my $is_table = 0; my $is_block = 0; my $block_sep_len = 3; # length of block separator ({{{), in can be >= 3 my $is_list = 0; my @table = (); my @block = (); MOINSCAN: while (<INFILE>) { # First of all remove all end whitespaces except \n s/\s*$/\n/; # Tables if (/\s*(?<line>\|\|.+\|\|\n)/ && !$is_block) { $is_table = 1; $is_list = 0; $_ = $+{line}; } elsif ($is_table) { $is_table = 0; @table = table_replacement(@table); print OUTFILE @table; @table = (); } # Code blocks parser s/\{{3}(.+?)}{3}/%%$1%%/g unless $is_block; # first remove all ignored blocks if (/(?<text>.*?)\s*(?<sep>\{{3,})(?<mod>.*\n)/ && !$is_block && !$is_table) { $block_sep_len = length $+{sep}; $is_block = 1; if ($is_list) { print OUTFILE "\n" } $is_list = 0; @block = ($+{mod}); next MOINSCAN unless ($+{text} && $+{text} !~ /^\s+$/); $_ = "$+{text}\n"; } elsif (/(?<data>.+?)}{$block_sep_len}\s*(?<text>.*)\n/ && $is_block) { $is_block = 0; push @block, "$+{data}\n" if $+{data}; @block = block_replacement(@block); print OUTFILE @block; @block = (); next MOINSCAN unless $+{text}; $_ = "$+{text}\n"; } elsif ($is_block) { push @block, $_; next MOINSCAN; } # Processing instructions s/##(.*)\n//; # comments s/#(pragma|format|redirect|refresh|language)(.*)\n//i; # remove all s/#deprecated(.*)\n/<note warning>This page is deprecated<note>\n/i; # deprecated # Other elements s/(<<BR>>)|(\[\[BR]])/\\\\ /g; # break s/^\s*-{4,}\s*$/----\n/g; # horizontal line s#^(.*)/\*(.+?)\*/(.*)\n#$1\n>$2\n$3\n#; # inline comments # Macros and another foolish - simply remove s/<<.+?>>//g; # macros # Headings my $s = "~!@>{"; s/^\s*=====\s*(.+?)\s*=====\s*$/$s$s $1 $s$s\n/g; # level 5 s/^\s*====\s*(.+?)\s*====\s*$/$s$s$s $1 $s$s$s\n/g; # level 4 s/^\s*===\s*(.+?)\s*===\s*$/$s$s$s$s $1 $s$s$s$s\n/g; # level 3 s/^\s*==\s*(.+?)\s*==\s*$/$s$s$s$s$s $1 $s$s$s$s$s\n/g; # level 2 s/^\s*=\s*(.+?)\s*=\s*$/$s$s$s$s$s$s $1 $s$s$s$s$s$s\n/g; # level 1 s/\Q$s\E/=/g; # Links s/ (?<br>[\[\{])\g{br} # opening brackets (?<target>[^\|]+?) # target (?:\|(?<text> # text (?(?=\{\{).+?}}|[^\|]+?) # test if text is an image link ))? (?:\|(?<params>[^\|]+?))? # parameters (??{ &inv($+{br}) x 2 }) # closing brackets / &link_replacement($namespace,$+{br},$+{target},$+{text},$+{params}) /gxe; # CamelCase links my $camel = '(?<![\\[!:])\b[A-Z]+[a-z]+[A-Z][A-Za-z]*\b'; # CamelCase link regex s#($camel)/($camel)#[[$1:$2]]#g; # CamelCase to namespace s#\.\./($camel)#[[$1]]#g; # (very)strange CamelCase s#/($camel)#[[$namespace:$1]]#g; # CamelCase to subpage s#($camel)#[[$1]]#g; # simlpe CamelCase # Avoid automating linking - simply remove s{''''''}<>g; s{``}<>g; s{!([A-Z]\w+)}<$1>g; # Text formatting s{'''''(.+?)'''''}<**//$1//**>g; # bold and italic s{'''(.+?)'''}<**$1**>g; # bold s{''(.+?)''}<//$1//>g; # italic s{`(.+?)`}<''$1''>g; # monospaced s{,,(.+?),,}{<sub>$1</sub>}g; # sub index s{\^(.+?)\^}{<sup>$1</sup>}g; # sup index s{--\((.+?)\)--}{<del>$1</del>}g; # strike through text # Unsupported text formating - simply remove s{~-(.+?)-~}<$1>g; # smaller text s{~\+(.+?)\+~}<$1>g; # larger text # Lists and intends if (/^(?<intend>\s+)\*\s*(?<value>\S.*)\n/) { # dotted list if ($is_list) { print OUTFILE "\n" } print OUTFILE " "x(2*length($+{intend})),"* "; $_ = $+{value}; $intend = length $+{intend}; $is_list = 1; } elsif (/^(?<intend>\s+)[1aAiI]\.(#\d+)?\s*(?<value>\S.*)\n/) { # numeric list if ($is_list) { print OUTFILE "\n" } print OUTFILE " "x(2*length($+{intend})),"- "; $_ = $+{value}; $intend = length $+{intend}; $is_list = 1; } elsif (/^(?<intend>\s+)(?<key>\S[^\[\{]+)::\s+(?<value>\S.*)\n/) { # definition list if ($is_list) { print OUTFILE "\n" } print OUTFILE "**$+{key}**\n"; print OUTFILE " * "; $_ = $+{value}; $intend = length $+{intend}; $is_list = 1; } elsif (/^(?<intend>\s+)(?<key>\S[^\[\{]+)::\s*/) { # definition if ($is_list) { print OUTFILE "\n" } print OUTFILE "**$+{key}**\n"; $_=""; $is_list = 0; } elsif (/^(?<intend>\s+)::\s*(?<value>\S.*)\n/) { # description if ($is_list) { print OUTFILE "\n" } print OUTFILE " * "; $_ = $+{value}; $intend = length $+{intend}; $is_list = 1; } elsif (/^(?<intend>\s+)(\.\s+)?\S/) { # simple leading whitespaces my $curr_intend = length $+{intend}; if ($curr_intend != $intend and $is_list) { print OUTFILE "\n\n"; $is_list = 0; } elsif ($curr_intend != $intend and !$is_list) { print OUTFILE "\n" } elsif ($curr_intend == $intend and $is_list) { print OUTFILE " "; s/\n$//; } $intend = $curr_intend; s/^\s*(\.\s*)?(?=\S)//; } else { # string witout leading whitespaces if ($is_list && ! /^\n/) { print OUTFILE "\n\n" } elsif ($intend) { print OUTFILE "\n" } $intend = 0; $is_list = 0; } # Smileys ;) foreach $smile (keys %smileys) { s/(\s|\A)\Q$smile\E(\s)/ $smileys{$smile}$2/g; } # Ok, print all results of abracadabra to file if we need it if ($is_block && $is_list) { $_ .= "\n" } if (!$is_table) { print OUTFILE $_ } else { push @table, $_ } } if ($is_table) { @table = table_replacement(@table); print OUTFILE @table; } if ($is_block) { @block = block_replacement(@block); print OUTFILE @block; } close INFILE or die "error\n"; close OUTFILE or die "error\n"; } # ----------------------------- End of Convert Function --------------------------------------- # ConvertMoinToDoku @ARGV;
Используется это дело так:
./convert.pl moin_file doku_file [namespace]
namespace
- это пространство имён, которое надо пихать в ссылки на картинки, если его не указать будет использоваться '.'.
К сожалению, оно не совсем корректно работает с таблицами (не учитывает склейку и выравнивание, первое является достаточно критичным), возможно потом допишу. Если вы вдруг будете это использовать - напишите мне о найденных ошибках или хотя бы оставьте тут комментарий.
- таблицы
- http://moinmo.in/HelpOnEditing - проверить, всё ли учли