如何在Scala中以惯用方式进行转义

时间:2014-02-18 13:49:22

标签: scala

假设我正在编写一个简单的函数来转义XML字符串。

val map = Map('&' -> "&amp;", '<' -> "&lt;", '>' -> "&gt;") // ... and more
def escape(str: String): String = {
  val w = new java.io.StringWriter()
  for(c <- str) if (map.contains(c)) w.write(map(c)) else w.write(c); 
  w.toString
}

它在Scala中看起来不是惯用的,而且,我不知道如何处理map,它将字符映射到转义字符串。你会怎么建议我解决它?

3 个答案:

答案 0 :(得分:10)

现实解决方案

只需使用scala.xml.Utility.escape

scala> scala.xml.Utility.escape(foo)
res7: String = &amp;foo&lt;bar&gt;hello

如果您仍然有兴趣自己动手:

首先,没有必要在转义地图中重复&;部分:

scala> val Escapes = Map('&' -> "amp", '<' -> "lt", '>' -> "gt")

(将它们放入其中更简单,更快......但是因为你似乎已经将这个问题用于学习目的......)

scala> def escapeChar(c: Char) = Escapes.get(c).map { x => s"&$x;" }
escapeChar: (c: Char)Option[String]

scala> def escapeStr(s: String) = s.flatMap { c => escapeChar(c).getOrElse(c.toString) }
escapeStr: (s: String)String

scala> escapeStr("&foo<bar>hello")
res9: String = &amp;foo&lt;bar&gt;hello

...您也可以内联escapeChar(c: Char)函数,但我认为这样更具可读性。

如果您感兴趣:这可以通过将字符串视为一系列字符来实现;你flatMap,它允许你将每个char映射到多个char(String);然后flatMap将所有发出的字符串连接成一个字符串。不需要转义的字符可以简单地映射到一个字符串。

答案 1 :(得分:5)

只是为了完整性 - 基本上是相同的解决方案,但用 function 方法代替地图:

def escape(char: Char) = char match {
     case '&' => "&amp;"
     case '<' => "&lt;"
     case '>' => "&gt;"
     case noEscaping  => noEscaping.toString 
}
val str = "hit & run"
str.flatMap(escape)
// hit &amp; run

答案 2 :(得分:4)

这个怎么样:

scala> val map = Map[Char, Seq[Char]]('&' -> "&amp;", 
       '<' -> "&lt;", 
       '>' -> "&gt;").withDefault(x => Seq(x))
map: scala.collection.immutable.Map[Char,Seq[Char]] = Map(& -> &amp;, < -> &lt;, > -> &gt;)

scala> "&foo<bar>hello".flatMap(map)
res2: String = &amp;foo&lt;bar&gt;hello

OR

scala> val map = Map('&' -> "&amp;", '<' -> "&lt;", '>' -> "&gt;").withDefault(identity)

scala> "&foo<bar>hello".map(map).mkString
res3: String = &amp;foo&lt;bar&gt;hello