MoinMoin to DokuWiki Сравнение версий

Различия

Здесь показаны различия между двумя версиями данной страницы.

Ссылка на это сравнение

Предыдущая версия справа и слева Предыдущая версия
Следующая версия
Предыдущая версия
wiki:moinmoin2dokuwiki [2009/07/21 02:21]
wiki:moinmoin2dokuwiki [2009/12/25 23:53] (текущий)
Строка 15: Строка 15:
 # ----------------------------------------------------------------------------------------------- # # ----------------------------------------------------------------------------------------------- #
  
-# Hash for smileys replacement ​(actual for ubuntu.com wiki)+# Hash for smileys replacement
 %smileys = ( %smileys = (
  #​moin doku  #​moin doku
Строка 60: Строка 60:
 } }
  
-Link  +Links  
-sub link_replacement ​+sub linkReplacement ​
- die "​Oops!\n" ​if @_ != 5;+ die "​Oops!\n" ​unless ​@_ == 5;
  my ($namespace,​$br,​$target,​$text,​$params) = @_;  my ($namespace,​$br,​$target,​$text,​$params) = @_;
  # Attachments links  # Attachments links
Строка 81: Строка 81:
 } }
  
-Block +Blocks 
-sub block_replacement ​{+sub blockReplacement ​{
  for (my $i = 0; $i < @_ && $_[$i] =~ /^\$*$/; $i++ ) { shift @_ } # delete empty lines  for (my $i = 0; $i < @_ && $_[$i] =~ /^\$*$/; $i++ ) { shift @_ } # delete empty lines
  for (my $i = -1; -$i <= @_ && $_[$i] =~ /^\$*$/; $i-- ) { pop @_ } # delete empty lines  for (my $i = -1; -$i <= @_ && $_[$i] =~ /^\$*$/; $i-- ) { pop @_ } # delete empty lines
Строка 96: Строка 96:
 } }
  
-Table +Tables 
-sub table_replacement ​{+sub tableReplacement ​{
  @table = @_;  @table = @_;
  for (@table) {  for (@table) {
Строка 107: Строка 107:
  "​|| ​ $2  " . '​|'​ x (length($1) - 2)  "​|| ​ $2  " . '​|'​ x (length($1) - 2)
  /ge;  /ge;
-Spanning+Span
  # TODO  # TODO
  # Aligment  # Aligment
Строка 150: Строка 150:
  } elsif ($is_table) {  } elsif ($is_table) {
  $is_table = 0;  $is_table = 0;
- @table = table_replacement(@table);+ @table = tableReplacement(@table);
  print OUTFILE @table;  print OUTFILE @table;
  @table = ();  @table = ();
Строка 164: Строка 164:
  next MOINSCAN unless ($+{text} && $+{text} !~ /^\s+$/);  next MOINSCAN unless ($+{text} && $+{text} !~ /^\s+$/);
  $_ = "​$+{text}\n";​  $_ = "​$+{text}\n";​
- } elsif (/​(?<​data>​.+?​)}{$block_sep_len}\s*(?<​text>​.*)\n/​ && $is_block) {+ } elsif (/​(?<​data>​.+?​)?}{$block_sep_len}\s*(?<​text>​.*)\n/​ && $is_block) {
  $is_block = 0;  $is_block = 0;
  push @block, "​$+{data}\n"​ if $+{data};  push @block, "​$+{data}\n"​ if $+{data};
- @block = block_replacement(@block);+ @block = blockReplacement(@block);
  print OUTFILE @block;  print OUTFILE @block;
  @block = ();  @block = ();
Строка 186: Строка 186:
  # Macros and another foolish - simply remove  # Macros and another foolish - simply remove
  s/<<​.+?>>//​g;​ #​ macros  s/<<​.+?>>//​g;​ #​ macros
- s/​\[\[.+?​]]//​g;​ #​ I dont know what is it 
  # Headings  # Headings
  my $s = "​~!@>​{";​  my $s = "​~!@>​{";​
Строка 205: Строка 204:
  (??{ &​inv($+{br}) x 2 }) # closing brackets  (??{ &​inv($+{br}) x 2 }) # closing brackets
  /  /
- &link_replacement($namespace,​$+{br},​$+{target},​$+{text},​$+{params})+ &linkReplacement($namespace,​$+{br},​$+{target},​$+{text},​$+{params})
  /gxe;   /gxe;
  # CamelCase links  # CamelCase links
Строка 229: Строка 228:
  s{~\+(.+?​)\+~}<​$1>​g;​ #​ larger text  s{~\+(.+?​)\+~}<​$1>​g;​ #​ larger text
  # Lists and intends  # Lists and intends
- if (/​^(?<​intend>​\s+)\*\s*(?<​value>​\S.*)\n/​) { # dotted list+ if (/​^(?<​intend>​\s+)\*\s+(?<​value>​\S.*)\n/​) { # dotted list
  if ($is_list) { print OUTFILE "​\n"​ }  if ($is_list) { print OUTFILE "​\n"​ }
  print OUTFILE " "​x(2*length($+{intend})),"​* ";  print OUTFILE " "​x(2*length($+{intend})),"​* ";
Строка 235: Строка 234:
  $intend = length $+{intend};  $intend = length $+{intend};
  $is_list = 1;  $is_list = 1;
- } elsif (/​^(?<​intend>​\s+)[1aAiI]\.(#​\d+)?​\s*(?<​value>​\S.*)\n/​) { # numeric list+ } elsif (/​^(?<​intend>​\s+)[1aAiI]\.(#​\d+)?​\s+(?<​value>​\S.*)\n/​) { # numeric list
  if ($is_list) { print OUTFILE "​\n"​ }  if ($is_list) { print OUTFILE "​\n"​ }
  print OUTFILE " "​x(2*length($+{intend})),"​- ";  print OUTFILE " "​x(2*length($+{intend})),"​- ";
Строка 289: Строка 288:
  }  }
  if ($is_table) {  if ($is_table) {
- @table = table_replacement(@table);+ @table = tableReplacement(@table);
  print OUTFILE @table;  print OUTFILE @table;
  }  }
  if ($is_block) {  if ($is_block) {
- @block = block_replacement(@block);+ @block = blockReplacement(@block);
  print OUTFILE @block;  print OUTFILE @block;
  }  }
Строка 316: Строка 315:
   * http://​moinmo.in/​HelpOnEditing - проверить,​ всё ли учли   * http://​moinmo.in/​HelpOnEditing - проверить,​ всё ли учли
 </​note>​ </​note>​
-{{tag>​DokuWiki Perl}}+ 
 +Абсолютно то же самое, только переписанное на Python, вдруг кому пригодится. Те же комментарии,​ таблицы обрабатываются не до конца и нужно не забыть заменить <​!/​code>​ на %%</​code>​%%:​ 
 + 
 +<code python>​ 
 +#​!/​usr/​bin/​env python 
 +# coding=utf8 
 + 
 +# Author: Vadim Nevorotin (malamut@ubuntu.ru) 
 +# License: GPLv3 
 + 
 +# Rus: 
 +# Скрипт конвертации разметки MoinMoin в разметку DokuWiki 
 +# Использование:​ moin2doku.py moin_file doku_file [namespace] 
 +# namespace - это пространство имён для всех ссылок на вложения (картинки,​ например) 
 + 
 +# Скрипт не до конца обрабатывает таблицы,​ не учитывается склейка ячеек и выравнивание 
 +# Так же не добавлена конвертация новой возможности moin: {{{#!wiki caution }}} и прочих выделений (http://​moinmo.in/​HelpOnAdmonitions) 
 +# Всё остальное с http://​moinmo.in/​HelpOnEditing на 11.2009 конвертируется в полном объёме 
 + 
 +# Eng: 
 + 
 +# Usage: ./​moin2doku.py moin_file doku_file [namespace] 
 +# namespace - for all links to images ({{namespace:​image.png}}) 
 + 
 +import sys 
 +import re 
 +from os.path import isfile 
 + 
 +# Hash for smileys replacement 
 +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>',​ 
 +
 + 
 +# Convert functions 
 + 
 +def inv(br): 
 + if br == '​{':​ return '​}'​ 
 + if br == '​[':​ return '​]'​ 
 + return br 
 + 
 +def linkReplacement(namespace,​br,​target,​text):​ 
 + if not target: 
 + print >> sys.stderr, "Fatal error"​ 
 + sys.exit(1) 
 + m_att = re.match('​(?:​(?:​attachment|drawing):​)(?​P<​att>​.+)$',​target) 
 + m_inter = re.match('​(.+?​):​(?​!//​)(.+)$',​target) 
 + # Attachments links 
 + if m_att: 
 + if m_att.group('​att'​):​ 
 + att = re.sub('​(.+)/','',​m_att.group('​att'​)) #​ leave only filename, without namespaces  
 + else: 
 + att = m_att.groups('​att'​) 
 + if text: 
 + return '​{{'​+namespace+':'​+att+'​|'​+text+'​}}'​ 
 + else: 
 + return '​{{'​+namespace+':'​+att+'​}}'​ 
 + # InterWiki links 
 + if m_inter: 
 + if text: 
 + return '​[['​+m_inter.group(1)+'>'​+m_inter.group(2)+'​|'​+text+'​]]'​ 
 + else: 
 + return '​[['​+m_inter.group(1)+'>'​+m_inter.group(2)+'​]]'​ 
 + # All other links simply returned in doku format 
 + if not re.search('://',​ target): # if target not an internet link replace all / to : (for namespaces) 
 + target = re.sub('/',':',​target) 
 + if text: 
 + return br + br + target + '​|'​ + text + inv(br) * 2 
 + else: 
 + return br + br + target + inv(br) * 2 
 + 
 +def tableReplacement(table):​ 
 + for i in range(len(table)):​ 
 + line = table[i] 
 + line = re.sub('​\|\|(?:​\s*(<​.+?>​))?​\s*(.+?​)\s*(?​=\|\|)',​ lambda m: '​||'​ + m.group(1) + m.group(2) if m.group(1) else '​||'​ + m.group(2), line) 
 + line = re.sub('​((?:​\|\|){2,​})(.+?​)(?​=\|\|)',​ lambda m: '​|| ​ '​+m.group(2)+' ​ ' + '​|'​ * (len(m.group(1)) - 2), line) 
 + line = re.sub('​\|\|(\s*)(?:<​.+?>​\s*?​)+(.*?​)(?​=\|\|)','​||\\1\\2',​ line) 
 + line = re.sub('​\|\|','​|',​ line) 
 + table[i] = line 
 + size = len(table) 
 + i = 0 
 + while i < size: 
 + if re.match('​\|+$',​table[i]):​ 
 + table.pop(i) 
 + size=size-1 
 + else: 
 + i=i+1 
 + return table 
 +  
 +def blockReplacement(block):​ 
 + if block and not block[0].strip():​ 
 + block.pop(0) 
 + if not block[-1].strip():​ 
 + block.pop() 
 + if not block: 
 + block.append('<​code>​\n'​) 
 + elif re.match('​\s*#​!python',​block[0]):​ 
 + block.pop(0) 
 + block.insert(0,'<​code python>​\n'​) 
 + elif re.match('​\s*#​!cplusplus',​block[0]):​ 
 + block.pop(0) 
 + block.insert(0,'<​code cpp>​\n'​) 
 + elif re.match('​\s*#​!java',​block[0]):​ 
 + block.pop(0) 
 + block.insert(0,'<​code java>​\n'​) 
 + elif re.match('​\s*#​!pascal',​block[0]):​ 
 + block.pop(0) 
 + block.insert(0,'<​code pascal>​\n'​) 
 + elif re.match('​\s*#​!.+',​block[0]):​ 
 + block.pop(0) 
 + block.insert(0,'<​code>​\n'​) 
 + else: 
 + block.insert(0,'<​code>​\n'​) 
 + block.append('<​!/​code>'​) 
 + return block 
 + 
 +def ConvertMoinToDoku(moin_file,​doku_file,​namespace):​ 
 + try: 
 + infile = open(moin_file,"​r"​) 
 + outfile = open(doku_file,"​w"​) 
 + except: 
 + print >> sys.stderr, "Open file error!"​ 
 + sys.exit(1) 
 +  
 + content=infile.readlines() 
 + infile.close() 
 +  
 + # Conversion 
 + st = '​~@!'​ #​ For headings conversion 
 + camel = '​(?<​![\\[!:​])\b[A-Z]+[a-z]+[A-Z][A-Za-z]*\b'​ #​ CamelCase regexp 
 + conversion = ( 
 + # Processing instructions 
 + ('​^##​(.*)\n',''​),​ 
 + ('​^#​(pragma|format|redirect|refresh|language)(.*)\n',''​),​ 
 + ('​^#​deprecated(.*)\n','<​note warning>​This page is deprecated<​note>​\n'​),​ 
 + # Other elements 
 + ('​(<<​BR>>​)|(\[\[BR]])','​\\\\ '), 
 + ('​^\s*-{4,​}\s*$','​----\n'​),​ 
 + ('​^(.*)/​\*(.+?​)\*/​(.*)\n','​\\1\n>​\\2\n\\3\n'​),​ #​ inline comments 
 + # Macros and another foolish - simply remove 
 + ('<<​.+?>>',''​),​ 
 + # Headings 
 + ('​^\s*=====\s*(.+?​)\s*=====\s*$',​st*2 + ' \\1 ' + st*2 + '​\n'​),​ 
 + ('​^\s*====\s*(.+?​)\s*====\s*$',​st*3 + ' \\1 ' + st*3 + '​\n'​),​ 
 + ('​^\s*===\s*(.+?​)\s*===\s*$',​st*4 + ' \\1 ' + st*4 + '​\n'​),​ 
 + ('​^\s*==\s*(.+?​)\s*==\s*$',​st*5 + ' \\1 ' + st*5 + '​\n'​),​ 
 + ('​^\s*=\s*(.+?​)\s*=\s*$',​st*6 + ' \\1 ' + st*6 + '​\n'​),​ 
 + (st,'​='​),​ 
 + # CamelCase links 
 + ('​('​+camel+'​)/​('​+camel+'​)','​[[\\1:​\\2]]'​),​ 
 + ('​\.\./​('​+camel+'​)','​[[\\1]]'​),​ 
 + ('/​('​+camel+'​)','​[['​+namespace+':​\\1]]'​),​ 
 + ('​('​+camel+'​)','​[[\\1]]'​),​ 
 + # Avoid automating linking - simply remove 
 + ("''''''",''​),​ 
 + ('​``',''​),​ 
 + ('​!([A-Z]\w+)','​\\1'​),​ 
 + # Text formatting 
 + ("'''''​(.+?​)'''''",'​**//​\\1//​**'​),​ 
 + ("'''​(.+?​)'''",'​**\\1**'​),​ 
 + ("''​(.+?​)''",'//​\\1//'​),​ 
 + ('​`(.+?​)`',"''​\\1''"​),​ 
 + (',,​(.+?​),,','<​sub>​\\1</​sub>'​),​ 
 + ('​\^(.+?​)\^','<​sup>​\\1</​sup>'​),​ 
 + ('​--\((.+?​)\)--','<​del>​\\1</​del>'​),​ 
 + # Unsupported text formating - simply remove 
 + ('​~-(.+?​)-~','​\\1'​),​ 
 + ('​~\+(.+?​)\+~','​\\1'​) 
 +
 +  
 + # Values for conversion 
 + intend = 0 
 + is_table = 0 
 + is_block = 0 
 + block_sep_len = 3 
 + is_list = 0 
 + table = [] 
 + block = [] 
 +  
 + for i in range(len(content)):​ 
 + line = content[i] 
 + # First of all remove all end whitespaces except \n 
 + line = re.sub('​\s*$','​\n',​line) 
 + # Tables 
 + m = re.search('​\s*(?​P<​line>​\|\|.+\|\|\n)',​line) 
 + if m and not is_block: 
 + is_table = 1 
 + is_list = 0 
 + line = m.group('​line'​) 
 + elif is_table: 
 + is_table = 0 
 + table = tableReplacement(table) 
 + outfile.writelines(table) 
 + table = [] 
 + # Code blocks parser 
 + if not is_block: 
 + line = re.sub('​\{{3}(.+?​)}{3}','​%%\\1%%',​line) 
 + m_open = re.search('​(?​P<​text>​.*?​)\s*(?​P<​sep>​\{{3,​})(?​P<​mod>​.*\n)',​line) 
 + m_close = re.search('​(?​P<​data>​.+?​)?​}{'​+str(block_sep_len)+'​}\s*(?​P<​text>​.*)\n',​line) 
 + if m_open and not is_block and not is_table: 
 + block_sep_len = len(m_open.group('​sep'​)) 
 + is_block = 1 
 + if is_list: 
 + outfile.write('​\n'​) 
 + is_list = 0 
 + block = [m_open.group('​mod'​)] 
 + if not ( m_open.group('​text'​) and not re.match('​\s+$',​m_open.group('​text'​)) ): 
 + continue 
 + line = m_open.group('​text'​) + '​\n'​ 
 + elif m_close and is_block: 
 + is_block = 0 
 + if m_close.group('​data'​):​ 
 + block.append(m_close.group('​data'​) + '​\n'​) 
 + block = blockReplacement(block) 
 + outfile.writelines(block) 
 + block = [] 
 + if not m_close.group('​text'​):​ 
 + continue 
 + line = m_close.group('​text'​) + '​\n'​ 
 + elif is_block: 
 + block.append(line) 
 + continue 
 + # Links 
 + # Unfortunately,​ Python is not a Perl, so we can't convert links using only one regexp... 
 + link = ''​ 
 + s = ''​ 
 + br = ''​ 
 + is_link = 0 
 + last = len(line)-1 
 + for i in range(len(line)):​ 
 + if not is_link and i != last and line[i] == '​['​ and line[i+1] == '​[':​ 
 + is_link = 1 
 + link = br = '​['​ 
 + elif not is_link and i != last and line[i] == '​{'​ and line[i+1] == '​{':​ 
 + is_link = 1 
 + link = br = '​{'​ 
 + elif is_link and line[i] == inv(br) and line[i-1] == inv(br): 
 + is_link = 0 
 + link = link + line[i] 
 + m = re.match('​(?​P<​target>​[^\|]+)(?:​\|(?​P<​text>​[^\|]+))?',​link[2:​-2]) 
 + link = linkReplacement(namespace,​link[0],​m.group('​target'​),​m.group('​text'​)) 
 + s = s + link 
 + elif is_link: 
 + link = link + line[i] 
 + else: 
 + s = s + line[i] 
 + line = s 
 + # Now convert syntax 
 + for r in conversion:​ 
 + reg=re.compile(r[0],​re.I) 
 + line=reg.sub(r[1],​line) 
 + # Lists and intends 
 + m_dotted = re.match('​(?​P<​intend>​\s+)\*\s+(?​P<​value>​\S.*)\n',​line) 
 + m_numeric = re.match('​(?​P<​intend>​\s+)[1aAiI]\.(#​\d+)?​\s+(?​P<​value>​\S.*)\n',​line) 
 + m_defs = re.match('​(?​P<​intend>​\s+)(?​P<​key>​\S[^\[\{]+)::​\s+(?​P<​value>​\S.*)\n',​line) 
 + m_def = re.match('​(?​P<​intend>​\s+)(?​P<​key>​\S[^\[\{]+)::​\s*',​line) 
 + m_desc = re.match('​(?​P<​intend>​\s+)::​\s*(?​P<​value>​\S.*)\n',​line) 
 + m_white = re.match('​(?​P<​intend>​\s+)(\.\s+)?​\S',​line) 
 + if m_dotted: 
 + if is_list: 
 + outfile.write('​\n'​) 
 + outfile.write("​ "​*(2*len(m_dotted.group('​intend'​)))+"​* ") 
 + line = m_dotted.group('​value'​) 
 + intend = len(m_dotted.group('​intend'​)) 
 + is_list = 1 
 + elif m_numeric:​ 
 + if is_list: 
 + outfile.write('​\n'​) 
 + outfile.write("​ "​*(2*len(m_numeric.group('​intend'​)))+"​- ") 
 + line = m_numeric.group('​value'​) 
 + intend = len(m_numeric.group('​intend'​)) 
 + is_list = 1 
 + elif m_defs: 
 + if is_list: 
 + outfile.write('​\n'​) 
 + outfile.write('​**'​+m_defs.group('​key'​)+'​**\n'​) 
 + outfile.write(' ​ * ') 
 + line = m_defs.group('​value'​) 
 + intend = len(m_defs.group('​intend'​)) 
 + is_list = 1 
 + elif m_def: 
 + if is_list: 
 + outfile.write('​\n'​) 
 + outfile.write('​**'​+m_def.group('​key'​)+'​**\n'​) 
 + line = ''​ 
 + is_list = 0 
 + elif m_desc: 
 + if is_list: 
 + outfile.write('​\n'​) 
 + outfile.write(' ​ * ') 
 + line = m_desc.group('​value'​) 
 + intend = len(m_desc.group('​intend'​)) 
 + is_list = 1 
 + elif m_white: 
 + curr_intend = len(m_white.groups('​intend'​)) 
 + if curr_intend != intend and is_list: 
 + outfile.write('​\n\n'​) 
 + is_list = 0 
 + elif curr_intend != intend and not is_list: 
 + outfile.write('​\n'​) 
 + elif curr_intend == intend and is_list: 
 + outfile.write('​ ') 
 + line = line.rstrip() 
 + intend = curr_intend 
 + line = re.sub('​^\s*(\.\s*)?​(?​=\S)','',​line) 
 + else: 
 + if is_list and not re.match('​\n',​line):​ 
 + outfile.write('​\n\n'​) 
 + elif intend: 
 + outfile.write('​\n'​) 
 + intend = 0 
 + is_list = 0 
 + # Smileys $) 
 + for smile in smileys.keys():​ 
 + line = re.sub('​(\s|\A)'​+re.escape(smile)+'​(\s)','​ '​+smileys[smile]+'​\\2',​line) 
 + # Finally... 
 + if is_block and is_list: 
 + line += '​\n'​ 
 + if not is_table: 
 + outfile.write(line) 
 + else: 
 + table.append(line) 
 + # If we haven'​t close some things 
 + if is_table: 
 + table = tableReplacement(table) 
 + outfile.writelines(table) 
 + if is_block: 
 + block = blockReplacement(block) 
 + outfile.writelines(block) 
 + outfile.close() 
 + 
 +# Main script... 
 + 
 +def PrintHelp():​ 
 + print """​Usage:​ moin2doku moin_file doku_file [namespace] 
 +Convert MoinMoin page to Doku, using namespace for pictures"""​ 
 + sys.exit(0) 
 + 
 +def PrintParameterError():​ 
 + print >> sys.stderr, "​Incorrect parameters! Use --help to read more information."​ 
 + sys.exit(1) 
 + 
 +def CheckParameters(moin_file,​doku_file):​ 
 + if not isfile(moin_file):​ 
 + print >> sys.stderr, "Moin file doesn'​t exists!"​ 
 + sys.exit(1) 
 + if not isfile(doku_file):​ 
 + print >> sys.stderr, "Doku file doesn'​t exists!"​ 
 + sys.exit(1) 
 + 
 +if __name__ == '​__main__':​ 
 + if len(sys.argv) > 1: 
 + if sys.argv[1] in ('​-h',​ '​--help'​):​ 
 + PrintHelp() 
 + elif len(sys.argv) > 2: 
 + moin_file = sys.argv[1] 
 + doku_file = sys.argv[2] 
 + if len(sys.argv) > 3: 
 + namespace = sys.argv[3] 
 + else: 
 + namespace = '​.'​ 
 + else: 
 + PrintParameterError() 
 + else: 
 + PrintParameterError() 
 +  
 + CheckParameters(moin_file,​doku_file) 
 +  
 + ConvertMoinToDoku(moin_file,​doku_file,​namespace) 
 +</​code>​ 
 + 
 +===== Улучшенная версия ===== 
 + 
 +Я ж ленивый,​ поэтому я написал '​обёртку'​ к представленной выше функции конвертации так, что бы её было удобно вызывать с различными аргументами и, кроме всего прочего,​ этот вариант умеет скачивать страницы и вложения из интернета. Функция конвертации здесь та же, просто она сопровождается удобным способом её вызывать. 
 + 
 +Описание см. в POD в коде. Не забудьте заменить <​!/​code>​ на </​code>​. 
 + 
 +<code perl> 
 +#​!/​usr/​bin/​perl -w 
 + 
 +use 5.010;​ #​ Для всяких выкрутасов,​ очень удобно 
 + 
 +use File::​Path;​ #​ Для управления каталогами 
 +use File::​Spec::​Functions;​ #​ Для склейки путей 
 +use Getopt::​Long;​ #​ Аргументики,​ разбираем аргументики 
 +use Pod::​Usage;​ #​ Для документации (всё равно пашет через пень-колоду) 
 + 
 +=begin comment 
 + 
 +Сначала идёт основная функция конвертации одного файла в другой,​ потом всякая ерунда,​ связанная с 
 +выкачкой вложений из интернета и разбором аргументов. Основную функцию как мог перевёл на аглицкий. 
 + 
 +Аргументы описываются ниже в основной программе,​ всё это написано just for fun, но если найдёте ошибку -  
 +сообщите мне, или, как вариант,​ исправьте прям в этом скрипте самостоятельно и не забудьте поместить его 
 +обратно на help.ubuntu.ru 
 + 
 +=end comment 
 + 
 +=cut 
 + 
 +# ----------------------------------------------------------------------------------------------- # 
 +#             ​Convert text file with MoinMoin Wiki syntax to DokuWiki syntax ​                     # 
 +#                          by Malamut (malamut@ubuntu.ru) (2009) ​                                 # 
 +# ----------------------------------------------------------------------------------------------- # 
 + 
 +# Hash for smileys replacement 
 +%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]; 
 +
 + 
 +# Links  
 +sub linkReplacement { 
 + die "​Oops!\n"​ unless @_ == 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 } 
 +
 + 
 +# Blocks 
 +sub blockReplacement { 
 + 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 @_; 
 +
 + 
 +# Tables 
 +sub tableReplacement { 
 + @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; 
 + # Span 
 + # 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 = tableReplacement(@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 = blockReplacement(@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 
 +
 + &​linkReplacement($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 = tableReplacement(@table);​ 
 + print OUTFILE @table; 
 +
 + if ($is_block) { 
 + @block = blockReplacement(@block);​ 
 + print OUTFILE @block; 
 +
 + close INFILE or die "​error\n";​ 
 + close OUTFILE or die "​error\n";​ 
 +
 + 
 +# ----------------------------- ​ End of Convert Function ​ --------------------------------------- # 
 + 
 +# ------------------------------------- ​ Функции ​ ----------------------------------------------- # 
 + 
 +# Создаёт директорию если её ещё нет (должна быть такая функция,​ но я не знаю :( ). Параметр - имя создаваемой директории 
 +sub CreateDir { 
 + die "​CreateDir:​ нужен один аргумент!\n"​ unless @_ == 1; 
 + if (! -e -d $_[0]) { 
 + mkdir $_[0] or die "Не могу создать '​$_[0]'​! ($!)\n";​ 
 +
 +
 + 
 +# Получает нужный файл из интернета с вики и пишет его в нужное местоъ 
 +# Первый параметр - адрес для скачивания 
 +# Второй параметр - файл, в который нужно сохранить результат 
 +sub GetUrlFile { 
 + die "​GetUrlFile:​ Должно быть ровно два аргумента\n"​ unless @_ == 2; 
 + my ($url, $filename) = @_; 
 + my $command = "wget -nv --user-agent '​Opera'​ -O '​$filename'​ '​$url'";​ 
 + if  (system $command ) { 
 + warn "​Невозможно получить или сохранить $url\n";​ 
 + return undef; 
 +
 +
 + 
 +# Получает все вложения из указанного файла по указанному адресу 
 +# Первый параметр - имя файла с moin разметкой 
 +# Второй параметр - базовый интернет-адрес вики 
 +# Третий параметр - адрес страницы на вики вместе с неймспейсом если нужно 
 +# Четвёртый параметр - папка куда складывать все скачанные файлы 
 +sub GetAttachments { 
 + die "​GetAttachments:​ Должно быть ровно четыре аргумента\n"​ unless @_ == 4; 
 + my ($moin,​$base_url,​$page_url,​$atts_dir) = @_; 
 + open INFILE, "<",​ $moin or die "Не могу открыть файл '​$moin'​!\n";​ 
 + while (<​INFILE>​) { 
 + if (my @atts = /​([\{\[])\1(?:​(?:​attachment|drawing):​)(.*?​)(??​{ &​inv($1) x 2 })/g) { 
 + for (my $i = 1; $i < @atts; $i+=2) { 
 + my ($namespace,​ $file) = $atts[$i] =~ m#​^(?:​(.+)/​)?​([^/​]+?​)$#;​ 
 + my $url = $namespace 
 + ? "​$base_url/​$namespace?​action=AttachFile&​do=get&​target=$file"​ 
 + : "​$base_url/​$page_url?​action=AttachFile&​do=get&​target=$file";​ 
 + CreateDir($atts_dir);​ 
 + GetUrlFile($url,​catfile($atts_dir,​$file));​ 
 + }  
 +
 +
 + close INFILE; 
 +
 + 
 +# ---------------------------- ​ Программа ​ ------------------------------------------------------- # 
 + 
 +=head1 NAME 
 + 
 +moin2doku.pl - преобразует разметку из MoinMoin в DokuWiki 
 + 
 +=head1 SYNOPSIS 
 + 
 +moin2doku.pl [options] files|urls 
 + 
 +=cut 
 + 
 +# Всякие (не)нужные переменные... 
 +my $help = 0; # показать помощь 
 +my $urls = 0; # воспринимать аргументы как url, а не как файлы (соответствует ключу -u) 
 +my $verbose = 0; # подробный вывод 
 + 
 +my $working_dir = "";​ #​ директория для сохранения всех результатов 
 +my $use_pagename_dir = 0; # использовать ли в качестве $working_dir имя страницы для каждой обработанной страницы 
 +my $attachments_dir = "";​ #​ директория для всяких картинок и прочего из {{attachment}} 
 + 
 +my $links = 1; # преобразовывать ли внутренние ссылки 
 + 
 +my $wiki_adress = "​localhost";​ #​ адрес вики 
 +my $wiki_namespace = "";​ #​ неймспейс на вики откуда брать страницы 
 + 
 +my $moin_file = "";​ #​ имя файла с моин разметкой для закачки при -u, если не указано - используется ИмяСтраницы.moin 
 +my $doku_file = "";​ #​ имя файла с доку разметкой,​ если не указано - используется ИмяСтраницы.txt или ИмяСтраницы.doku 
 + 
 +# Задаёт нужные параметры для русских статей с wiki.ubuntu.com 
 +sub ru_official_wiki { 
 + $wiki_adress = '​https://​wiki.ubuntu.com';​ 
 + $wiki_namespace = '​RussianDocumentation';​ 
 +
 + 
 +Getopt::​Long::​Configure ("​bundling"​);​ #​ Конфигурирование getopt дабы воспринимать склейку коротких аргументов 
 +GetOptions( 
 + "​verbose|v+"​ => \$verbose,​ #​ TODO: подробный вывод 
 + "​delete-internal-links|l"​ => \$links,​ #​ TODO: удалять внутренние ссылки,​ а не преобразовывать 
 + "​urls|u"​ => \$urls,​ #​ воспринимать параметры как интернет-ссылки 
 + "​moin-file|m=s"​ => \$moin_file,​ #​ имя файла с moin разметкой,​ по умолчанию - ИмяСтраницы.moin 
 + "​doku-file|d=s"​ => \$doku_file,​ #​ имя файла с doku разметкой,​ по умолчанию - ИмяСтраницы.txt или ИмяСтраницы.doku если занято 
 + "​use-pagename-dir|n"​ => \$use_pagename_dir,​ #​ использовать для каждой страницы её имя в качестве working-directory 
 + "​wiki-adress|w=s"​ => \$wiki_adress,​ #​ адрес вики, с которой качаем 
 + "​wiki-namespace|N=s"​ => \$wiki_namespace,​ #​ неймспейс на вики, в котором искать страницы 
 + "​working-directory|D=s"​ => \$working_dir,​ #​ директория для сохранения всех результатов 
 + "​attachments-directory|A=s"​ => \$attachments_dir,​ #​ поддиректория для картинок и по совместительству неймспейс для вложений,​ по умолчанию - имя страницы 
 + "​ru-official-wiki|r"​ => \&​ru_official_wiki,​ #​ ага, всем лень, мне тоже 
 + "​help|h"​ => \$help);​ #​ ну понятно 
 + 
 +=head1 OPTIONS 
 + 
 +=over 8 
 + 
 +=item B<-A имя, --attachments-directory=имя>​ 
 + 
 +Имя директории для складывания всех скачанных вложений при B<​-u>,​ а так же имя пространства имён, указываемого при конвертировании всех вложений. 
 + 
 +=item B<-d файл, --doku-file=файл>​ 
 + 
 +Файл для сохранения сконвертированного в DokuWiki разметку результата. По умолчанию используется ИмяСтраницы.txt или, если такой файл уже существует,​ ИмяСтраницы.doku 
 + 
 +=item B<-D директория,​ --working-directory=директория>​ 
 + 
 +Директория в которую будут сложены все результаты. По умолчанию всё складывается в текущую. 
 + 
 +=item B<-l, --delete-internal-links>​ 
 + 
 +Удалять все внутренние ссылки,​ а не преобразовывать их (не работает) 
 + 
 +=item B<-m файл, --moin-file=файл>​ 
 + 
 +Имя файла, в котором будет сохранён скачанный исходный код страницы в moin разметке. По умолчанию для каждой статьи используется ИмяСтатьи.moin 
 + 
 +=item B<-n, --use-pagename-dir>​ 
 + 
 +Использовать для каждой страницы её имя в качестве директории для сохранения всех результатов. 
 + 
 +=item B<-N имя, --wiki-namespace=имя>​ 
 + 
 +Путь до пространства имён, в котором будут искаться указанные статьи,​ от корня вики. 
 + 
 +=item B<-u, --urls>​ 
 + 
 +Воспринимать все агрументы как имена статей на вики по адресу,​ заданному ключами B<-N> и B<​-w>​ 
 + 
 +=item B<-v, --verbose>​ 
 + 
 +Подробный вывод (не работает) 
 + 
 +=item B<-w адрес, --wiki-adress>​ 
 + 
 +Интернет-адрес вики, с которой брать страницы при указании ключа B<​-u>​ 
 + 
 +=back 
 + 
 +=cut 
 + 
 +if ($help) { 
 + pod2usage(-verbose => 1); 
 +
 +unless (@ARGV) { 
 + pod2usage(-verbose => 1); 
 +
 + 
 +if (!$use_pagename_dir && ($moin_file || $doku_file) && @ARGV > 1) { 
 + warn "​При указании жёстких имён для moin или doku файлов указанный файл будет использован для всех аргументов ". 
 + "и будет в итоге содержать текст только для последней обработанной страницы\n";​ 
 +
 + 
 +if ($urls) { 
 + if ($working_dir && !$use_pagename_dir) { 
 + CreateDir($working_dir);​ 
 + chdir $working_dir or die "​Невозможно сменить директорию на '​$working_dir'​! ($!)\n";​ 
 +
 + for my $page (@ARGV) { 
 + if ($page =~ m<[/ ]>) { die "​Имя страницы не может содержать символы '/',​ ' ' ($_)\n"​ } 
 + $wiki_adress =~ s#/$##; # Удаляем завершающий / если он имеется 
 + $wiki_namespace =~ s#/$##; # Удаляем завершающий / если он имеется 
 + if ($use_pagename_dir) { 
 + CreateDir($page);​ 
 +
 + # Получаем исходники страницы 
 + my $source_url = $wiki_namespace ? "​$wiki_adress/​$wiki_namespace/​$page?​action=raw"​ : "​$wiki_adress/​$page?​action=raw";​ 
 + my $moin_source = $moin_file ? $moin_file : "​$page.moin";​ 
 + $moin_source = catfile($page,​$moin_source) if $use_pagename_dir;​  
 + GetUrlFile($source_url,​$moin_source);​ 
 + # Получаем вложения 
 + my $atts_dir = $attachments_dir ? $attachments_dir : $page; 
 + $atts_dir = catdir($page,​$atts_dir) if $use_pagename_dir;​ 
 + GetAttachments($moin_source,​$wiki_adress,​ $wiki_namespace ? "​$wiki_namespace/​$page"​ : $page, $atts_dir);​ 
 + # Теперь конвертируем 
 + my $doku_result = $doku_file ? $doku_file : "​$page.txt";​ 
 + $doku_result = catfile($page,​$doku_result) if $use_pagename_dir;​ 
 + unless ($attachments_dir) { ConvertMoinToDoku($moin_source,​$doku_result,​$page) } 
 + else { ConvertMoinToDoku($moin_source,​$doku_result,​$attachments_dir) } 
 +
 +} else { 
 + for my $file (@ARGV) { 
 + # Берём имя страницы отбрасывая расширение файла 
 + my ($page) = $file =~ m#​^(?:​.*/​)([^/​]+?​)(?:​\.[^\./​]+)?​$#;​ 
 + # Выбираем имя выходного файла 
 + my $doku_result = $doku_file ? $doku_file : "​$page.txt";​ 
 + if ($use_pagename_dir) { 
 + CreateDir($page);​ 
 + $doku_result = catfile($page,​$doku_result);​ 
 + } elsif ($working_dir) { 
 + CreateDir($working_dir);​ 
 + $doku_result = catfile($working_dir,​$doku_result);​ 
 +
 + if (-e $doku_result) { $doku_result =~ s/​\.txt$/​.doku/​ } 
 + # Конвертируем 
 + unless ($attachments_dir) { ConvertMoinToDoku($file,​$doku_result,​$page) } 
 + else { ConvertMoinToDoku($file,​$doku_result,​$attachments_dir) } 
 +
 +
 + 
 +__END__ 
 + 
 +=head1 DESCRIPTION 
 + 
 +описания пожалуй не будет - лень писать. Лучше всего использовать так: 
 +moin2doku -run статья для url и 
 +moin2doku -n файл для обычных файлов 
 + 
 +=head1 AUTHOR 
 + 
 +Скрипт написал Malamut just for fun :) Со всеми вопросами и пожеланиями обращайтесь:​ malamut@ubuntu.ru 
 + 
 +=head1 BUGS 
 + 
 +Некорректно работает параметр -h поскольку весь этот текст написан на русском,​ вообще что-то Pod::Usage как-то странно работает с русским текстом. 
 +На данный момент некорректно обрабатываются таблицы - не учитывается выравнивание и склейка через colspan и rowspan. 
 +Кроме того, не работают параметры B<-v> и B<​-l>​. 
 + 
 +=cut 
 +</​code>​ 
 + 
 +{{tag>​DokuWiki Perl Программирование}}