一部のHTMLタグを通すフィルタ
Posted feedbacks - Scala
ライブラリを使ったら面白くないので、自分で書いてみた。思ったよりすっきりかけた気がする。
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 | 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(
"""(</?)([^"'< >]*)([^"'<>]*(?:"[^"]*"[^"'<>]*|'[^']*'[^"'<>]*)*)((?:>|(?=<)|$(?!\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 apply(html:String) = {
html.gsub(tagRegex, (m:Matcher) => {
val tag = m.group(2).toLowerCase.replace("/","")
(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 {
""
}
})
List(m.group(1),m.group(2), attrs, m.group(4))
}else {
List(m.group(1).replace("<", "<"), m.group(2), m.group(3), m.group(4))
}).mkString("")
})
}
}
println(htmlEscape("""<a href='www.google.com'>link</a> <blink>and</blink> <strong onClick='alert("NG")'>click<br/>me!</strong>"""))
|



にしお
#3410()
Rating0/0=0.00
このお題はperezvonさんの提案を元にしています。ありがとうございました。 ただ、いきなりだと難しいかと思ったので、肝の部分以外を先に出題しました。このお題は続編で徐々に難しくなっていきます。
追記:属性に<や>が含まれてしまうケースに漏れのある解答が多いようなのでテストケースを追加します。 これは「この出力なら十分」という意味です。この出力の通りでなければいけないという意味ではありません。 <script foo="<script>alert('bar')</script>">alert('foo')</script> <script foo="<script>alert('bar')</script>">alert('foo')</script> <script foo="<a href='link'>link</a>">alert('foo')</script> <script foo="<a href='link'>link</a>">alert('foo')</script> <a href='www.g>oogle.com'>link</a> <a href="./www.g%3Eoogle.com">link</a>[ reply ]