pomu0325さんのブログ記事のコードを拡張してみた。
もともとのコードは「http://」ではじまる部分をリンクタグへ変換していたが、今回の拡張で次の二つの変換を追加した
def linkURL(s: String): NodeSeq = { import util.matching._ class FirstMatch(pattern: Regex) { def c2s(c: CharSequence): String = c.toString def unapply(s: String) = pattern.findFirstMatchIn(s) map { case m => (c2s(m.before), m.matched, c2s(m.after)) } } val link = new FirstMatch("""http://[\d\w\-\./%?=#]+""".r) val reply = new FirstMatch("""@[a-zA-Z0-9]+""".r) val hashtag = new FirstMatch("""#[a-zA-Z0-9]+""".r) s match { case link(before, s, after) => linkURL(before) ++ <a href={s}>{xml.Text(s)}</a> ++ linkURL(after) case reply(before, s, after) => val href = "http://twitter.com/"+s.drop(1) linkURL(before) ++ <a href={href}>{xml.Text(s)}</a> ++ linkURL(after) case hashtag(before, s, after) => val href = "/?q="+Helpers.urlEncode(s) linkURL(before) ++ <a href={href}>{xml.Text(s)}</a> ++ linkURL(after) case s => xml.Text(s) } }
これはさらに次のように拡張できる。次の例はTwitterのAPIが返す文字列がhtmlエンコードされているのを安全に戻している。
def linkURL(s: String): NodeSeq = { import util.matching._ class FirstMatch(pattern: Regex) { def c2s(c: CharSequence): String = c.toString def unapply(s: String) = pattern.findFirstMatchIn(s) map { case m => (c2s(m.before), m.matched, c2s(m.after)) } } val link = new FirstMatch("""http://[\d\w\-\./%?=#]+""".r) val reply = new FirstMatch("""@[a-zA-Z0-9]+""".r) val hashtag = new FirstMatch("""#[a-zA-Z0-9]+""".r) val amp = new FirstMatch("&".r) val lt = new FirstMatch("<".r) val gt = new FirstMatch(">".r) val quote = new FirstMatch(""".r) s match { case link(before, s, after) => linkURL(before) ++ <a href={s}>{xml.Text(s)}</a> ++ linkURL(after) case reply(before, s, after) => val href = "http://twitter.com/"+s.drop(1) linkURL(before) ++ <a href={href}>{xml.Text(s)}</a> ++ linkURL(after) case hashtag(before, s, after) => val href = "/?q="+Helpers.urlEncode(s) linkURL(before) ++ <a href={href}>{xml.Text(s)}</a> ++ linkURL(after) case lt(before,_,after) => linkURL(before) ++ xml.Text("<") ++ linkURL(after) case gt(before,_,after) => linkURL(before) ++ xml.Text(">") ++ linkURL(after) case quote(before,_,after) => linkURL(before) ++ xml.Text("\"") ++ linkURL(after) case amp(before,_,after) => linkURL(before) ++ xml.Text("&") ++ linkURL(after) case s => xml.Text(s) } }