Димо обнови решението на 22.11.2011 22:34 (преди почти 13 години)
+class Checker
+ def is_code? str
+ /^ .*$/.match str
+ end
+
+ def is_heading? str
+ /^[\s]*[#]{1,4}[ \t\r\f]+[\S]+.*/.match str
+ end
+
+ def is_quote? str
+ /^[\s]*>[ \t\r\f]+.*\n?/.match str
+ end
+
+ def is_olist? str
+ /^[\s]*[\d]+\.[\s].*$/.match str
+ end
+
+ def is_ulist? str
+ /^[\s]*\*[^\*].*$/.match str
+ end
+
+ def is_empty? str
+ /^[\s]*$/.match str
+ end
+end
+
+class Replacer
+ def replace_heading mo
+ tmp = /([#]+)(.*)/.match mo.to_s
+ len = tmp.to_a[1].size
+ text = tmp.to_a[2].to_s.strip
+ "<h" + len.to_s + ">" + replace_s_s(text) + "</h" + len.to_s + ">\n"
+ end
+
+ def replace_quote mo
+ text = mo.to_s[1..-1]
+ "<blockquote>" + replace_s_s(text.strip) + "</blockquote>\n"
+ end
+
+ def replace_par str
+ "<p>" + replace_s_s(str) + "<\/p>\n"
+ end
+
+ def replace_s_s str
+ str.strip.gsub(/[&<>"]/,
+ { "&" => "&", "<" => "<", ">" => ">", "\"" => """ })
+ end
+
+ def replace_olist mo
+ text = mo.to_s.gsub(/[\d]+./, "")
+ "<ol>\n <li>" + replace_s_s(text.strip) + "<\/li>\n<\/ol>\n"
+ end
+
+ def replace_ulist mo
+ text = mo.to_s.gsub(/^[\s]*\*/, "")
+ "<ul>\n <li>" + replace_s_s(text.strip) + "<\/li>\n<\/ul>\n"
+ end
+
+ def replace_code mo
+ "<pre><code>" + replace_s_s('a' + mo.to_s[4..-1] + 'a')[1..-2] + "</code></pre>\n"
+ end
+
+ def remove str
+ tmp = str.gsub(/<\/code><\/pre>\n<pre><code>/, "\n")
+ tmp = tmp.gsub(/<\/blockquote>\n<blockquote>/, "\n")
+ tmp = tmp.gsub(/<\/ol>\n<ol>\n/, "")
+ tmp = tmp.gsub(/<\/ul>\n<ul>\n/, "")
+ tmp = tmp.gsub(/(?<=<blockquote>).+?(?=<\/blockquote>)/m) { |str| make_pars str }
+ tmp = tmp.gsub(/<\/p>\n<\/blockquote>/, "<\/p><\/blockquote>")
+ tmp.gsub(/<\/p>\n<p>/, "\n")
+ end
+
+ def make_pars str
+ str.to_s.each_line.inject("") { |a, b| a +
+ ((/^[\s]*$/.match b) ? b : ("<p>" + b.strip + "<\/p>\n")) }
+ end
+
+ def add_link str
+ unless /(\[[^\n\]]+\])(\([^\n\)]+\))/.match str
+ return str
+ end
+ a = /(\[[^\n\]]+\])(\([^\n\)]+\))/.match str
+ tmp = "<a href=\"" + a.to_a[2][1..-2] + "\">" + a.to_a[1][1..-2] + "<\/a>"
+ str.gsub(/(\[[^\n\]]+\])(\([^\n\)]+\))/, tmp)
+ end
+end
+
+class Font
+ def make_fonts str
+ str = str.each_line.inject("") { |a, b| a + strong_line(b) }
+ str.each_line.inject("") { |a, b| a + em_line(b) }
+ end
+
+ def match_code str
+ /<pre><code>.*?<\/code><\/pre>/m.match str
+ end
+
+ def strong_line str
+ if match_code str
+ return str
+ end
+ i = 0
+ while i < str.size do
+ if /\*\*.+?\*\*/.match str, i
+ str = make_strong(str, i)
+ end
+ i += 1
+ end
+ str
+ end
+
+ def em_line str
+ if match_code str
+ return str
+ end
+ i = 0
+ while i < str.size do
+ if /_.+?_/.match str, i
+ str = make_em(str, i)
+ end
+ i += 1
+ end
+ str
+ end
+
+ def make_strong str, i
+ a = str.match /\*\*.+?\*\*/, i
+ if(a.pre_match.count("_") % 2 == 1 and a.to_s.include? "_")
+ return str
+ end
+ a.pre_match + "<strong>" + a.to_s[2..-3] + "<\/strong>" + a.post_match
+ end
+
+ def sub_count str, subs
+ str.each_char.each_cons(subs.size).select {|s| s == subs.split(//)}.count
+ end
+
+ def make_em str, i
+ a = str.match /_.+?_/, i
+ if sub_count(a.pre_match, "<strong>") % 2 == 1 and sub_count(a.to_s, "<strong>") > 0
+ return str
+ end
+ a.pre_match + "<em>" + a.to_s[1..-2] + "<\/em>" + a.post_match
+ end
+end
+
+class Formatter
+ attr_accessor :raw_text, :c, :r, :f
+
+ def initialize str
+ @raw_text = str
+ @c = Checker.new
+ @r = Replacer.new
+ @f = Font.new
+ end
+
+ def to_html
+ convert @raw_text
+ end
+
+ def to_s
+ to_html
+ end
+
+ def inspect
+ @raw_text
+ end
+
+ def convert str
+ res = f.make_fonts r.remove(str.each_line.inject("") { |a, b| a + convert_line(b) })
+ res.strip
+ end
+
+ def convert_line str
+ if c.is_code? str then return r.replace_code c.is_code? str end
+ if c.is_heading? str then return r.add_link r.replace_heading c.is_heading? str end
+ if c.is_quote? str then return r.add_link r.replace_quote c.is_quote? str end
+ if c.is_olist? str then return r.add_link r.replace_olist c.is_olist? str end
+ if c.is_ulist? str then return r.add_link r.replace_ulist c.is_ulist? str end
+ if c.is_empty? str then return str
+ else r.add_link r.replace_par str
+ end
+ end
+end