Scala:我怎样才能获得字符串的转义表示?

时间:2012-03-28 18:58:43

标签: string scala escaping

基本上,我想做的是:

 // in foo.scala
 val string = "this is a string\nover two lines"
 println(string)
 println(foo(string))

这样做:

% scala foo.scala
this is a string
over two lines
"this is a string\nover two lines"

基本上寻找类似ruby的String#inspect或haskell的show :: String -> String

6 个答案:

答案 0 :(得分:21)

我很确定这在Scala或Java的标准库中不可用,但它在Apache Commons Lang中:

scala> import org.apache.commons.lang.StringEscapeUtils.escapeJava
import org.apache.commons.lang.StringEscapeUtils.escapeJava

scala> escapeJava("this is a string\nover two lines")
res1: java.lang.String = this is a string\nover two lines

当然,如果您愿意,可以轻松地将引号添加到转义字符串中。

答案 1 :(得分:21)

这个问题有点陈旧但我在自己寻找解决方案时偶然发现了它并且对其他答案不满意,因为它们要么不安全(自己更换东西)要么需要外部库。

我找到了一种方法来获取scala标准库(> 2.10.0)的字符串的转义表示,这是安全的。它使用了一个小技巧:

通过运行时反射,您可以轻松获得文字字符串表达式的表示。在调用它的toString方法时,这种表达式的树将作为(几乎)scala代码返回。这尤其意味着文字以代码的方式表示,即转义和双引号。

def escape(raw: String): String = {
  import scala.reflect.runtime.universe._
  Literal(Constant(raw)).toString
}

escape函数因此导致所提供的原始字符串的所需代码表示(包括周围的双引号):

scala> "\bHallo" + '\n' + "\tWelt"
res1: String =
?Hallo
        Welt

scala> escape("\bHallo" + '\n' + "\tWelt")
res2: String = "\bHallo\n\tWelt"

这个解决方案无疑会滥用反射api,但恕我直言仍然比其他提出的解决方案更安全,更可维护。

答案 2 :(得分:5)

scala.reflect解决方案实际上运行正常。当你不想引入整个库时,这就是它在幕后所做的事情(Scala 2.11):

def quote (s: String): String = "\"" + escape(s) + "\""
def escape(s: String): String = s.flatMap(escapedChar)

def escapedChar(ch: Char): String = ch match {
  case '\b' => "\\b"
  case '\t' => "\\t"
  case '\n' => "\\n"
  case '\f' => "\\f"
  case '\r' => "\\r"
  case '"'  => "\\\""
  case '\'' => "\\\'"
  case '\\' => "\\\\"
  case _    => if (ch.isControl) "\\0" + Integer.toOctalString(ch.toInt) 
               else              String.valueOf(ch)
}

val string = "\"this\" is a string\nover two lines"
println(quote(string)) // ok

答案 3 :(得分:2)

如果我编译这些:

object s1 {
val s1 = "this is a string\nover two lines"
}

object s2 {
val s2 = """this is a string
over two lines"""
}

我没有发现字符串的区别,所以我猜:没有可能找出源中是否有“\ n”。

但也许我弄错了,你想两者都得到相同的结果?

 "\"" + s.replaceAll ("\\n", "\\\\n").replaceAll ("\\t", "\\\\t") + "\""

第二种可能性是:

val mask = Array.fill (3)('"').mkString 
mask + s + mask

res5: java.lang.String = 
"""a
b"""

测试:

scala> val s = "a\n\tb"
s: java.lang.String = 
a
    b

scala>     "\"" + s.replaceAll ("\\n", "\\\\n").replaceAll ("\\t", "\\\\t") + "\""
res7: java.lang.String = "a\n\tb"

scala> mask + s + mask
res8: java.lang.String = 
"""a
    b"""

答案 4 :(得分:2)

如果您不想使用apache库,则可以非常轻松地构建自己的函数:

scala> var str = "this is a string\b with some \n escapes \t so we can \r \f \' \" see how they work \\";
str: java.lang.String = 
this is a string? with some 
escapes      so we can 
' " see how they work \

scala> print(str.replace("\\","\\\\").replace("\n","\\n").replace("\b","\\b").replace("\r","\\r").replace("\t","\\t").replace("\'","\\'").replace("\f","\\f").replace("\"","\\\""));
this is a string\b with some \n escapes \t so we can \r \f \' \" see how they work \\

答案 5 :(得分:0)

也许在 Scala 3 中有一种更简洁的方法来实现这一点,但这是我按照 @martin-ring 方法提出的:

import scala.quoted.*

inline def escape(inline raw: String): String = ${escapeImpl('{raw})}

def escapeImpl(raw: Expr[String])(using Quotes): Expr[String] =
  import quotes.reflect.*
  Literal(StringConstant(raw.show)).asExprOf[String]