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

Mic*_*ael 0 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
}
Run Code Online (Sandbox Code Playgroud)

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

Eri*_*lun 10

现实生活中的解决

只需使用scala.xml.Utility.escape:

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

如果你仍然有兴趣自己做:

首先,没有必要重复转义映射中的&;部分:

scala> val Escapes = Map('&' -> "amp", '<' -> "lt", '>' -> "gt")
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)

...你也可以只是内联escapeChar(c: Char)函数,但我认为这种方式更具可读性.

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


om-*_*nom 5

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

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
Run Code Online (Sandbox Code Playgroud)