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

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

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

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

Posted feedbacks - Scala

2706をベースにしてます。
 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
import java.util.regex._
class ExtendedString(self:String) {
  def gsub(reg:Pattern, f:(Matcher)=>String):String = {
    val result = new StringBuffer
    val m = reg.matcher(self)
    while(m.find) m.appendReplacement(result, f(m))
    m.appendTail(result)
    result.toString
  }
  def gsub(reg:String, f:(Matcher)=>String):String = gsub(Pattern.compile(reg), f)
}
implicit def string2ext(self:String) = new ExtendedString(self);

object htmlEscape{
  lazy val tagRegex = Pattern.compile(
    """(<\s*/?\s*)([^"'<\s>]*\s*)([^"'<>]*(?:"[^"]*"[^"'<>]*|'[^']*'[^"'<>]*)*)((?:>|(?=<)|$(?!\n)))"""
  )
  lazy val attrRegex = Pattern.compile(
    """[\s'"](\w+)\s*=\s*([^\s'">]+|'[^']+'|\"[^"]+")"""
  , Pattern.DOTALL | Pattern.CASE_INSENSITIVE)

  lazy val tagAllowed  = Set("a", "br", "strong")
  lazy val attrAllowed = Map("a" -> Set("href", "name"))

  def replace(s:String, rs:Pair[String,String]*) = {
    rs.foldLeft(s){(r,v)=> r.replace(v._1, v._2)}
  }
  def apply(html:String) = {
    val other = tagRegex.split(html)
    val sb    = new StringBuilder
    val m     = tagRegex.matcher(html)
    var i = -1;while({
      i=i+1;
      try{
        sb.append(replace(other(i), ("<","&lt;"), (">","&gt;"), ("\n","<br/>")));
      }catch{case _=> ()};
      m.find}
    ) {
      val tag = replace(m.group(2).toLowerCase, ("/","")).trim
      sb.append(
        (if(tagAllowed.contains(tag)){
          val attrs = m.group(3).gsub(attrRegex, (m2:Matcher) => {
            if(attrAllowed.getOrElse(tag, Set[String]()).contains(m2.group(1).toLowerCase)) {
              m2.group(0)
            }else {
              ""
            }
          })
          if(tag == "br") List("<br/>")
          else List(m.group(1),m.group(2), attrs, m.group(4))
        }else {
          List(replace(m.group(1), ("<", "&lt;")), m.group(2), 
               replace(m.group(3), ("<", "&lt;"), (">", "&gt;")), m.group(4))
        }).mkString("")
      )
    }
    sb.toString
  }
}

Index

Feed

Other

Link

Pathtraq

loading...