如何在Scala中实现“unes​​cape”?

时间:2014-03-17 07:10:35

标签: scala

这是我之前question

的后续内容

感谢答案,我意识到escape函数实际上是 flatMap,其参数为f:Char => Seq[Char],用于将转义字符映射到转义序列(请参阅答案) )。

现在我想知道如何将unescape作为反向操作实施到escape。我想这应该与flatMap相反,参数为f:Seq[Char] => Char。是否有意义 ?您如何建议实施unescape

2 个答案:

答案 0 :(得分:2)

  

我想这应该是与flatMap相反的函数f:Seq [Char] =>字符。是否有意义 ?

不是真的。您的反函数f:Seq[Char] => Char应该在"abc"上返回什么?它应该适用于任何字符序列并返回单个字符。您可以尝试使用PartialFunction[Seq[Char], Char],但是您会遇到其他问题。您是否将其应用于输入的每个后续步骤?

更通用的解决方案是将foldLeft与累加器类型一起使用,该累加器类型包含结果的构建部分和转义序列,类似于(未经测试):

def unescape(str: String) = {
  val result = str.foldLeft[(String, Option[String])](("", None)) { case ((acc, escapedAcc), c) => 
    (c, escapedAcc) match {
      case ('&', None) =>
        (acc, Some(""))
      case (_, None) =>
        (acc + c, None)
      case ('&', Some(_)) =>
        throw new IllegalArgumentException("nested escape sequences")
      case (';', Some(escapedAcc1)) => 
        (acc + unescapeMap(escapedAcc1), None)
      case (_,  Some(escapedAcc1)) =>
        (acc, Some(escapedAcc1 + c))
    }
  }

  result match {
    case (escaped, None) =>
      escaped
    case (_, Some(_)) => 
      throw new IllegalArgumentException("unfinished escape sequence")
  }
}

val unescapeMap = Map("amp" -> "&", "lt" -> "<", ...)

(将StringBuilder用于累加器会更有效,但这更容易理解。)

但是对于这个特定情况,您可以将字符串拆分为&,然后将除;之外的每个部分分开,然后以这种方式获取您想要的部分。

答案 1 :(得分:1)

这似乎是my own answerthe question的后续行动,其后续问题是......使用scala.xml.Utility.unescape

val sb = new StringBuilder
scala.xml.Utility.unescape("amp", sb)
println(sb.toString) // prints &

或者如果你只想忘记一次并扔掉StringBuilder实例:

scala.xml.Utility.unescape("amp", new StringBuilder).toString // returns "&"

这只是解析个人逃脱;你必须自己构建一个包含整个XML字符串的解析器 - 接受的答案似乎提供了一点但却无法重新发明scala.xml.Utility轮 - 或者使用来自scala.xml的东西。