Иван обнови решението на 23.11.2011 00:01 (преди почти 13 години)
+# Known issues (feeling sick, might break something if I don`t stop)
+# quote/whitespace handling is ugly as hell
+
+class Formatter #not completely implemented yet
+ def initialize(raw_markdown)
+ @raw_markdown = raw_markdown
+ end
+
+ def to_html
+ chopped = @raw_markdown.chomp
+ chopped.strip! unless chopped.start_with? ' '
+ bloated = paragraphs(code_segments(white_space(chopped))).chomp
+
+ bloated.gsub(/[ ]+(<\/?p>)/u, '\1').gsub(/^[ ]{4}/u, '')
+ end
+
+ alias to_s to_html
+
+ def white_space(raw_text)
+ corrected = raw_text.gsub(/(?<=^)[ ]{,3}(\S.+?)[ ]*(?=$)/u, '\1')
+ corrected = corrected.gsub(/^[ ]{,3}(\S[^\n]+)[ ]*([\n$]+)/u,'\1\2')
+ #next, we predictably break blockquotes!
+ corrected.gsub!(/^((>[ ]+[^\n]*[\n]??)\g<2>*?)([\n]{2}|[\n][^>]|\Z)/um,
+ "<blockquote>\n\\1\n</blockquote>\\3")
+ corrected.gsub! /(^)[>][ ]+/, '\1' #and help paragraph wrapping
+
+ corrected
+ end
+
+ def paragraphs(raw_string) #processes every line not starting with [ <]
+ done = raw_string.gsub(/^([#]{1,4})[ ]+(\S.*)$/u) do
+ process_simple_tags "<h#{$1.length}>#{escape_specials $2}</h#{$1.length}>"
+ end
+
+ done.gsub!(/^(([^ <\n][^\n]+[\n]??)\g<2>*?)([\n]{2}|[\n][\Z<]|\Z)/um) do
+ par = "<p>#{escape_specials $1}</p>#{$3}"
+ par = process_simple_tags par
+ end
+
+ done.gsub("<blockquote>\n", '<blockquote>').gsub("\n</blockquote>",'</blockquote>')
+ end
+
+ def code_segments(bare_code_string)
+ code = bare_code_string
+ code.gsub!(/([\n]{2,}|^)(^\s{4}(.*?))([\n][\S\n]|\Z)/um) do
+ "#{$1}<pre><code>#{escape_specials $3}</code></pre>#{$4}"
+ end
+ code.gsub!(/^((\*[ ][^\n]+[\n\Z]?)\g<1>*)/um) { "<ul>\n#{$1.chomp}\n</ul>\n" }
+ code.gsub!(/^((\d+\.[ ][^\n]+[\n\Z]?)\g<1>*)/um) { "<ol>\n#{$1.chomp}\n</ol>\n" }
+ code.gsub!(/^(\*|\d+\.)[ ](.+)$/u) do
+ process_simple_tags " <li>#{escape_specials $2}</li>"
+ end
+
+ code
+ end
+
+ def process_simple_tags(from='')
+ processed = from.gsub(/([^\[]*)\[([^\]]+)\]\(([^)]+)\)(.*)/u,
+ '\1<a href="\3">\2</a>\4')
+ processed = recurse_beutification processed
+
+ processed
+ end
+
+ def recurse_beutification(ugly_version)
+ ugly_version.gsub(/(?<!\w)(_|\*{2})(.+?)\1(?!\w)/u) { strong_or_em $~ }
+ end
+
+ def strong_or_em(matchdata)
+ case matchdata[1]
+ when '_' then "<em>#{recurse_beutification matchdata[2]}</em>"
+ when '**' then "<strong>#{recurse_beutification matchdata[2]}</strong>"
+ else matchdata[2]
+ end
+ end
+
+ def escape_specials(from='')
+ from.gsub(/&/, '&').gsub(/</, '<').gsub(/(?<!^)>/, '>').gsub(/"/, '"')
+ end
+
+ def inspect
+ @raw_markdown
+ end
+end
Проблемът ти с линковете е в регулярния израз, не в String#gsub
.
Последната част на шаблона ти е (.*)
, която ти "изяжда" останалия текст още при първия опит за match и за втори опит за match не остава текст. Това парче е излишно и трябва да го махнеш. По същата логика, излишно парче от шаблона е и водещото ([^\[]*)
.
Като ги махнеш, изразът, с който заменяш, ще стане:
'<a href="\2">\1</a>'
Мдаа ... в момента като го гледам не мога да се сетя каква ми беше идеята да изглежда по точно този начин. Възможно е да съм го оставил така от някоя предишна ревизия (в която е имало смисъл), но определено края е трябвало да е non-greedy ...
Мерси много, ще мога да спя спокойно като му дойде времето :)