MarkdownからHTMLへ変換するスクリプト


手でHTMLタグを書くのは面倒臭いので(ほぼ素のnvimを使っているので補完も使えないし)、Rubyで簡素なコードを書いた。Pandocを使ってもいいのだけど、昔使っていたころ、確か改行するために空行をわざわざ作らなければいけなかったっけ、と思い出し自作することにした。

パーサーとか生成規則とかよくわからないので正規表現でやっている。CommonMarkなどの仕様に従ったものではないし、対応している構文も私が使っているものだけ


使い方

対応している構文とか

仕様

今後出来るようにしたいこと


ソースコード

def main
  text = ""
  bcode = false
  ul = false # ul内
  ol = false # ol内

  file = open(ARGV[0], "r")

  while line = file.gets
    line.rstrip!
    # 一部の記号を文字参照に置き換える
    line.gsub!(/&/, "&")
    line.gsub!(/</, "&lt;")
    line.gsub!(/>/, "&gt;")
    line.gsub!(/"/, "&quot;")

    # Heading
    if /^\#{1,6}\s/.match(line)
      hlen = /^\#{1,6}/.match(line)[0].length
      line.sub!(/^\#{1,6}\s/, "")
      line = "<h" + hlen.to_s + ">" + line + "</h" + hlen.to_s + ">"

      line = inline(line)
      text += line + "\n"

    # Unordered List
    elsif ul and !/^-\s[^\s]/.match?(line) and !/^\*\s[^\s]/.match?(line) # list end
      ul = false
      text += "</ul>\n"
    elsif /^-\s[^\s]/.match?(line) || /^\*\s[^\s]/.match?(line)
      if !ul
        text += "<ul>\n"
        ul = true
      end

      line = inline(line)
      if /^-/.match?(line)
        text += "<li>" + /^-\s(.*)$/.match(line)[1] + "</li>\n"
      elsif /^*/.match?(line)
        text += "<li>" + /^*\s(.*)$/.match(line)[1] + "</li>\n"
      end

    # Ordered List
    elsif ol and !/^\d+?\.\s/.match?(line) # list end
      ol = false
      text += "</ol>\n"
    elsif /^\d+?\.\s/.match?(line)
      if !ol
        ol = true
        text += "<ol>\n"
      end

      line = inline(line)
      text += "<li>" + /^\d+?\.\s(.*)$/.match(line)[1] + "</li>\n"

    # blockcode
    elsif /^```/.match?(line)
      if bcode
        bcode = false
        text += "</pre>\n"
      else
        bcode = true
        text += "<pre>\n"
      end
    elsif bcode
      text += line + "\n"
    # blank
    elsif line == ""
      text += "<br>\n"
    # para
    else
      line = inline(line)
      text += "<p>" + line + "</p>\n"
    end
  end
  file.close
  return text
end

def inline(line)
  # [link](link.link)
  while link = /(.|^)(\[[^\[\]]+?\]\([^\(\)]+?\))(.|$)/.match(line)
    html = "<a href=\"" + /\((.*?)\)$/.match(link[2])[1] + "\">" + /^\[(.*?)\]\(/.match(link[2])[1] + "</a>"
    line.sub!(link[2], html)
  end
  # *em*
  while em = /([^*]|^)(\*[^*]+?\*)(.|$)/.match(line)
    html = "<em>" + /^\*([^*]+?)\*$/.match(em[2])[1] + "</em>"
    line.sub!(em[2], html)
  end
  # **strong**
  while strong = /([^*]|^)(\*\*[^*]+?\*\*)(.|$)/.match(line)
    html = "<strong>" + /^\*\*([^*]+?)\*\*$/.match(strong[2])[1] + "</strong>"
    line.sub!(strong[2], html)
  end
  # `code`
  while code = /([^`]|^)(`[^`]+?`)([^`]|$)/.match(line)
    html = "<code>" + /^`([^`]+?)`$/.match(code[2])[1] + "</code>"
    line.sub!(code[2], html)
  end
  return line
end

html = main
puts html