コンテンツにスキップ

利用者:Ef3/MarkdownToWikitext

出典: フリー教科書『ウィキブックス(Wikibooks)』
#!/usr/bin/env ruby
# frozen_string_literal: true

# Markdown to Wikitext converter

class MarkdownToWikitext
  def initialize
    @in_table = false
    @in_code_block = false
    @code_language = nil
    @table_rows = []
    @current_table_row = []
    @table_header = false
  end

  def lang(lang_text)
      return "text" unless lang_text
      return "text" if lang_text == ""
      { 
          "python" => "python3",
          "javascript" => "js",
          
      }[lang_text] || lang_text
  end
  
  def convert(markdown_text)
    result = []
    lines = markdown_text.split("\n")

    i = 0
    while i < lines.length
      line = lines[i]

      # Check for code blocks
      if line.strip.start_with?('```')
        if @in_code_block
          # End of code block
          @in_code_block = false
          result << '
'
       else
         # Start of code block
         @in_code_block = true
         language = line.strip.delete_prefix('```').strip
         @code_language = lang(language)

result << ":

"
        end
        i += 1
        next
      end

      # Check for tables
      if line.strip.start_with?('|') && !@in_code_block
        unless @in_table
          @in_table = true
          @table_rows = []
          @table_header = true
        end

        # Parse table row
        cells = line.split('|').map(&:strip)
        cells.shift if cells.first.empty? # Remove leading empty cell
        cells.pop if cells.last.empty?    # Remove trailing empty cell

        if @table_header && line.strip.match(/^\|(\s*[-:]+\s*\|)+/)
          # This is the separator row, skip it
          @table_header = false
          i += 1
          next
        end

        @table_rows << cells
        i += 1

        # Check if this is the end of the table
        if i >= lines.length || !lines[i].strip.start_with?('|')
          result << generate_wiki_table
          @in_table = false
        end
        next
      elsif @in_table
        # End of table encountered
        result << generate_wiki_table
        @in_table = false
      end

      result << if @in_code_block
                  # Inside code block, add as is
                  line
                else
                  # Process normal markdown
                  convert_line(line)
                end

      i += 1
    end

    # Handle any remaining table
    result << generate_wiki_table if @in_table

    result.join("\n")
  end

  private

  def convert_line(line)
    # Process headings
    if line.match(/^(#+)(.+)$/)
      equals = '=' * (1 + $1.size)
      return "#{equals} #{$2.strip} #{equals}"
    end

    # Process bold and italic
    line = line.gsub(/\*\*\*(.+?)\*\*\*/, "''''\\1''''") # Bold and italic
    line = line.gsub(/\*\*(.+?)\*\*/, "'''\\1'''")       # Bold
    line = line.gsub(/\*(.+?)\*/, "''\\1''")             # Italic
    line = line.gsub(/__(.+?)__/, "'''\\1'''") # Bold (underscore)
    line = line.gsub(/_(.+?)_/, "''\\1''") # Italic (underscore)

    # Process links
    line = line.gsub(/\[(.+?)\]\((.+?)\)/, '[\\2 \\1]') # External links

    # Process inline code
    line = line.gsub(/`(.+?)`/, '<code>\\1</code>')

    # Process horizontal rule
    line = '----' if line.match(/^[*\-_]{3,}$/)

    # Process unordered lists
    line = "*#{line.sub(/^[-*]\s+/, ' ')}" if line.strip.start_with?('- ', '* ')

    # Process ordered lists
    line = "##{line.sub(/^\d+\.\s+/, ' ')}" if line.match(/^\d+\.\s+/)

    line
  end

  def generate_wiki_table
    return '' if @table_rows.empty?

    # Process cells for nested syntax highlighting
    @table_rows.each_with_index do |row, i|
      row.each_with_index do |cell, j|
        # Check for inline code blocks within table cells
        next unless cell.include?('```')

        parts = cell.split('```')
        processed_cell = parts[0]

        if parts.length > 1
          (1...parts.length).each do |k|
            if k.odd? # Code block content
              lng = parts[k].split("\n").first.strip
              code = parts[k].split("\n")[1..].join("\n")
              processed_cell += ":<syntaxhighlight lang=\"#{lang(lng)}\">\n#{code}\n</syntaxhighlight copy>"
            else # Normal text
              processed_cell += convert_line parts[k]
            end
          end
        end

        @table_rows[i][j] = processed_cell
      end
    end

    # Generate the MediaWiki table
    result = ['{|class="wikitable"']

    # Add header row
    if @table_rows.length.positive?
      result << '|-'
      header_row = @table_rows[0]
      header_row.each do |cell|
        result << "!#{convert_line cell}"
      end
    end

    # Add data rows
    (1...@table_rows.length).each do |i|
      row = @table_rows[i]
      result << '|-'
      row.each do |cell|
        result << "|#{convert_line cell}"
      end
    end

    result << '|}'
    result.join("\n")
  end
end

markdown_text = File.read('text.md')
converter = MarkdownToWikitext.new
wikitext = converter.convert(markdown_text)
last = nil
wikitext.split("\n").each {
  puts _1 if _1 != last && !(last && last[0] == '#' && _1 == '')
  last = _1
}