Решение на Пета задача от Тони Ризов

Обратно към всички решения

Към профила на Тони Ризов

Резултати

  • 8 точки от тестове
  • 0 бонус точки
  • 8 точки общо
  • 57 успешни тест(а)
  • 0 неуспешни тест(а)

Код

class Matcher
def match_head(line)
/\A\s*\#{1,4}\s+\S+/ =~ line
end
def match_code(line)
/\A {4}/ =~ line
end
def match_quote(line)
/\A\s*>\s+/ =~ line
end
def match_list(line)
/\A\s*((\d+\. )|(\* ))/ =~ line
end
def match_ordered_list(line, count)
/\A\s*#{ count }\. / =~ line
end
def match_unordered_list(line)
/\A\s*\* / =~ line
end
def match_paragraph(line)
return false if match_head line
return false if match_code line
return false if match_list line
return false if match_quote line
true
end
end
class Parser
def initialize
@matcher = Matcher.new
end
def parse_head(line)
count = /\#{1,4}/.match(line).to_s.length
text = parse_special_chars /\#{1,4}/.match(line).post_match.strip
parse_strong_em parse_link "<h#{ count }>#{ text }</h#{ count }>\n"
end
def parse_link(text)
text.gsub(/\[([^\]]+)\]\(([^\)]+)\)/) do |match|
'<a href="' + $2 + '">' + $1 + '</a>'
end
end
def parse_unordered_list(lines, index)
html = "<ul>\n"
while index < lines.length and @matcher.match_unordered_list lines[index]
el = parse_link parse_special_chars /\*/.match(lines[index]).post_match.strip
html += " <li>" + parse_strong_em(el) + "</li>\n"
index += 1
end
[html + "</ul>\n", index]
end
def parse_ordered_list(lines, index, count)
html = "<ol>\n"
while index < lines.length and @matcher.match_ordered_list(lines[index], count)
el = parse_link parse_special_chars /\./.match(lines[index]).post_match.strip
html += " <li>" + parse_strong_em(el) + "</li>\n"
index += 1
count += 1
end
[html + "</ol>\n", index]
end
def parse_strong_em(text)
text = text.gsub(/\*\*([^\*]*)\*\*/) do |match|
'<strong>' + $1 + '</strong>'
end
text = text.gsub(/_([^_]*)_/) do |match|
'<em>' + $1 + '</em>'
end
text = text.gsub(/<strong>(.*)<\/strong>/) do |match|
collision?($1, '<em>', '</em>') ? '**' + $1 + '**' : match
end
text.gsub(/<em>(.*)<\/em>/) do |match|
collision?($1, '<strong>', '</strong>') ? '_' + $1 + '_' : match
end
end
def collision?(text, start, finish)
count = 1
index = -finish.length
while (index = text.index(finish, index + finish.length)) do
return true if text[0..index].scan(start).length < count
count += 1
end
false
end
def parse_special_chars(text)
text.gsub(/[&<>"]/, '&' => '&amp;', '<' => '&lt;', '>' => '&gt;', '"' => '&quot;')
end
def parse_paragraph(lines, index)
html = ""
in_par = false
while index < lines.length and @matcher.match_paragraph lines[index]
html, in_par = parse_line(html, lines[index].strip, in_par)
index += 1
end
[html.chomp("\n") + (in_par ? "</p>" : "") + "\n", index]
end
def parse_line(html, line, in_par)
if line == '' and in_par
[html.chomp("\n") + "</p>\n\n", false]
elsif line == '' and not in_par
[html + "\n", false]
else
line = parse_link parse_special_chars line
[html + (in_par ? "" : "<p>") + parse_strong_em(line) + "\n", true]
end
end
end
class Formatter
def initialize(text)
@text = text
@parser = Parser.new
@matcher = Matcher.new
end
def parse_list(lines, index)
if @matcher.match_unordered_list lines[index]
@parser.parse_unordered_list(lines, index)
else
@parser.parse_ordered_list(lines, index, /\d+/.match(lines[index]).to_s.to_i)
end
end
def parse_code(lines, index)
html = '<pre><code>'
while index < lines.length and @matcher.match_code lines[index]
html += @parser.parse_special_chars(lines[index][4..lines[index].length]) + "\n"
index += 1
end
[html.chomp("\n") + "</code></pre>\n", index]
end
def parse_quote(lines, index)
html = '<blockquote>'
paragraph = []
while index < lines.length and @matcher.match_quote lines[index]
line = /> /.match(lines[index]).post_match.rstrip
paragraph << line
index += 1
end
['<blockquote>' + parse_text("", paragraph, 0) + "</blockquote>\n", index]
end
def parse_other(lines, index)
if @matcher.match_code lines[index]
parse_code(lines, index)
elsif @matcher.match_list lines[index]
parse_list(lines, index)
elsif @matcher.match_quote lines[index]
parse_quote(lines, index)
else
[@parser.parse_head(lines[index]), index + 1]
end
end
def parse_text(html, lines, index)
while index < lines.length
if @matcher.match_paragraph lines[index]
parsed = @parser.parse_paragraph(lines, index)
else
parsed = parse_other(lines, index)
end
html += parsed[0]
index = parsed[1]
end
html.strip
end
def to_html
parse_text("", @text.split("\n"), 0)
end
def to_s
to_html
end
def inspect
@text
end
end

Лог от изпълнението

.........................................................

Finished in 0.62029 seconds
57 examples, 0 failures

История (1 версия и 0 коментара)

Тони обнови решението на 22.11.2011 01:00 (преди почти 13 години)

+class Matcher
+ def match_head(line)
+ /\A\s*\#{1,4}\s+\S+/ =~ line
+ end
+
+ def match_code(line)
+ /\A {4}/ =~ line
+ end
+
+ def match_quote(line)
+ /\A\s*>\s+/ =~ line
+ end
+
+ def match_list(line)
+ /\A\s*((\d+\. )|(\* ))/ =~ line
+ end
+
+ def match_ordered_list(line, count)
+ /\A\s*#{ count }\. / =~ line
+ end
+
+ def match_unordered_list(line)
+ /\A\s*\* / =~ line
+ end
+
+ def match_paragraph(line)
+ return false if match_head line
+ return false if match_code line
+ return false if match_list line
+ return false if match_quote line
+ true
+ end
+end
+
+class Parser
+ def initialize
+ @matcher = Matcher.new
+ end
+
+ def parse_head(line)
+ count = /\#{1,4}/.match(line).to_s.length
+ text = parse_special_chars /\#{1,4}/.match(line).post_match.strip
+ parse_strong_em parse_link "<h#{ count }>#{ text }</h#{ count }>\n"
+ end
+
+ def parse_link(text)
+ text.gsub(/\[([^\]]+)\]\(([^\)]+)\)/) do |match|
+ '<a href="' + $2 + '">' + $1 + '</a>'
+ end
+ end
+
+ def parse_unordered_list(lines, index)
+ html = "<ul>\n"
+ while index < lines.length and @matcher.match_unordered_list lines[index]
+ el = parse_link parse_special_chars /\*/.match(lines[index]).post_match.strip
+ html += " <li>" + parse_strong_em(el) + "</li>\n"
+ index += 1
+ end
+ [html + "</ul>\n", index]
+ end
+
+ def parse_ordered_list(lines, index, count)
+ html = "<ol>\n"
+ while index < lines.length and @matcher.match_ordered_list(lines[index], count)
+ el = parse_link parse_special_chars /\./.match(lines[index]).post_match.strip
+ html += " <li>" + parse_strong_em(el) + "</li>\n"
+ index += 1
+ count += 1
+ end
+ [html + "</ol>\n", index]
+ end
+
+ def parse_strong_em(text)
+ text = text.gsub(/\*\*([^\*]*)\*\*/) do |match|
+ '<strong>' + $1 + '</strong>'
+ end
+ text = text.gsub(/_([^_]*)_/) do |match|
+ '<em>' + $1 + '</em>'
+ end
+ text = text.gsub(/<strong>(.*)<\/strong>/) do |match|
+ collision?($1, '<em>', '</em>') ? '**' + $1 + '**' : match
+ end
+ text.gsub(/<em>(.*)<\/em>/) do |match|
+ collision?($1, '<strong>', '</strong>') ? '_' + $1 + '_' : match
+ end
+ end
+
+ def collision?(text, start, finish)
+ count = 1
+ index = -finish.length
+ while (index = text.index(finish, index + finish.length)) do
+ return true if text[0..index].scan(start).length < count
+ count += 1
+ end
+ false
+ end
+
+ def parse_special_chars(text)
+ text.gsub(/[&<>"]/, '&' => '&amp;', '<' => '&lt;', '>' => '&gt;', '"' => '&quot;')
+ end
+
+ def parse_paragraph(lines, index)
+ html = ""
+ in_par = false
+ while index < lines.length and @matcher.match_paragraph lines[index]
+ html, in_par = parse_line(html, lines[index].strip, in_par)
+ index += 1
+ end
+ [html.chomp("\n") + (in_par ? "</p>" : "") + "\n", index]
+ end
+
+ def parse_line(html, line, in_par)
+ if line == '' and in_par
+ [html.chomp("\n") + "</p>\n\n", false]
+ elsif line == '' and not in_par
+ [html + "\n", false]
+ else
+ line = parse_link parse_special_chars line
+ [html + (in_par ? "" : "<p>") + parse_strong_em(line) + "\n", true]
+ end
+ end
+end
+
+class Formatter
+ def initialize(text)
+ @text = text
+ @parser = Parser.new
+ @matcher = Matcher.new
+ end
+
+ def parse_list(lines, index)
+ if @matcher.match_unordered_list lines[index]
+ @parser.parse_unordered_list(lines, index)
+ else
+ @parser.parse_ordered_list(lines, index, /\d+/.match(lines[index]).to_s.to_i)
+ end
+ end
+
+ def parse_code(lines, index)
+ html = '<pre><code>'
+ while index < lines.length and @matcher.match_code lines[index]
+ html += @parser.parse_special_chars(lines[index][4..lines[index].length]) + "\n"
+ index += 1
+ end
+ [html.chomp("\n") + "</code></pre>\n", index]
+ end
+
+ def parse_quote(lines, index)
+ html = '<blockquote>'
+ paragraph = []
+ while index < lines.length and @matcher.match_quote lines[index]
+ line = /> /.match(lines[index]).post_match.rstrip
+ paragraph << line
+ index += 1
+ end
+ ['<blockquote>' + parse_text("", paragraph, 0) + "</blockquote>\n", index]
+ end
+
+ def parse_other(lines, index)
+ if @matcher.match_code lines[index]
+ parse_code(lines, index)
+ elsif @matcher.match_list lines[index]
+ parse_list(lines, index)
+ elsif @matcher.match_quote lines[index]
+ parse_quote(lines, index)
+ else
+ [@parser.parse_head(lines[index]), index + 1]
+ end
+ end
+
+ def parse_text(html, lines, index)
+ while index < lines.length
+ if @matcher.match_paragraph lines[index]
+ parsed = @parser.parse_paragraph(lines, index)
+ else
+ parsed = parse_other(lines, index)
+ end
+ html += parsed[0]
+ index = parsed[1]
+ end
+ html.strip
+ end
+
+ def to_html
+ parse_text("", @text.split("\n"), 0)
+ end
+
+ def to_s
+ to_html
+ end
+
+ def inspect
+ @text
+ end
+end