challenge 改行をBRタグに置き換える

一部のHTMLタグを通すフィルタ どう書く?の続編です。 前回の条件を満たしつつ、入力中の改行を<br/>に置き換えてください。ただし、たとえば"<a\nhref=...>"といったようにタグの中に改行がある場合、単純に置換するわけには行かないことに注意してください。

また、ユーザの入力注の<br>は<br/>に変換してください。

このお題はperezvonさんの提案を元にした三部作の二問目です。ご協力ありがとうございました。

Posted feedbacks - Ruby

これ難しいですねえ。
あらゆる入力に対して大丈夫かは自信がもてません。
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
require 'cgi'

def div(s, reg)
  return [s] if s !~ reg
  ($` != "" ? [$`] : []) + [$&] + div($', reg)
end

def quo(state, r, sym)
  case state.last
  when sym
    state.pop
    state.slice!(-2, 2) if state[-2,2] == [:hrf, :eql]
    r
  when :atr then ""
  else
    state.push(sym)
    r
  end
end

def tag(state, r, sym, s)
  case state.last
  when :sgl, :dbl then "&lt;#{s}"
  else
    state.push(sym)
    state.push(:atr)
    r
  end
end

def kak(state, r)
  case state.last
  when :sgl, :dbl
    if state[-2] == :eql && state[-3] == :hrf
      CGI.escape(r)
    else
      CGI.escapeHTML(r)
    end
  else
    CGI.escapeHTML(r)
  end
end

def filter(s)
  state = [:nml]

  div(s, %r{(<a|<br|<strong|</|<|>|=|&|\"|\'|\n)}i).map{|r|
    case r
    when /'/        then quo(state, r, :sgl)
    when /"/        then quo(state, r, :dbl)
    when /<a/i      then tag(state, r, :a,   "a")
    when /<br/i     then tag(state, r, :br,  "br")
    when /<strong/i then tag(state, r, :str, "strong")
    when /<\//
      case state.last
      when :a, :br, :str    then state[-1] = :cls; r
      else                  "&lt;/"
      end
    when /</
      kak(state, r)
    when />/
      case state.last
      when :atr             then state.pop; (state.last==:br ? "/" : "") + r
      when :cls, :hrf, :eql then state.pop; r
      else                  kak(state, r)
      end
    when /href/i
      case state.last
      when :atr             then state[-2] == :a ? (state.push(:hrf); r) : ""
      else                  r
      end
    when /name/i
      case state.last
      when :atr             then state[-2] == :a ? (state.push(:hrf); r) : ""
      else                  r
      end
    when /\=/
      case state.last
      when :hrf             then state.push(:eql); r
      when :atr             then ""
      else                  r
      end
    when /\n/
      case state.last
      when :nml, :a         then "<br/>"
      when :atr             then state[-2] == :a ? " " : ""
      end
    when /&/
      "&amp;"
    else
      case state.last
      when :atr             then ""
      else                  r
      end
    end
  }.join
end

if __FILE__ == $0
  a = DATA.read.split(/DELIM\n/)

  while true
    pr = a.slice!(0,2)
    puts filter(pr[0]) == pr[1]
    break if a.empty?
  end
end

__END__
<a foo="" href='www.g>oogle.com'>link</a>DELIM
<a href='www.g%3Eoogle.com'>link</a>DELIM
<script foo="<script>alert('bar')</script>">alert('foo')</script>DELIM
&lt;script foo="&lt;script&gt;alert('bar')&lt;/script&gt;"&gt;alert('foo')&lt;/script&gt;DELIM
<script foo="<a href='link'>link</a>">alert('foo')</script>DELIM
&lt;script foo="&lt;a href='link'&gt;link&lt;/a&gt;"&gt;alert('foo')&lt;/script&gt;DELIM

Index

Feed

Other

Link

Pathtraq

loading...