String Scala:如何获得字符串的转义表示?

String Scala:如何获得字符串的转义表示?,string,scala,escaping,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::S

基本上,我想做的是:

 // 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
的类似物,如果我编译这些:

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或Java的标准库中都没有这一功能,但它存在于:


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

如果不想使用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 \\

这个问题有点老了,但我自己在寻找解决方案时被它绊倒了,对其他答案不满意,因为它们要么不安全(自己替换东西),要么需要外部库

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

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

def escape(raw: String): String = {
  import scala.reflect.runtime.universe._
  Literal(Constant(raw)).toString
}
因此,
escape
函数将生成所提供原始字符串的所需代码表示形式(包括周围的双引号):


无可否认,此解决方案滥用了反射api,但仍然比其他建议的解决方案更安全、更易于维护。

scala.reflect解决方案实际上运行良好。当您不想拉进整个库时,这似乎是它在引擎盖下所做的(Scala 2.11):


在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]

(U) 我正在寻找一个转义字符串的函数,其中转义字符串涉及将所有的“\n”转换为“\\n”、“\t”转换为“\\t”等,并可能将结果用双引号括起来(取决于语言)。编译时,至少将\n转换为0A(如果您碰巧通过hexeditor查看)。我敢打赌,您将看到\t的等效项-与使用tab键的tab相同。好的-在字符串前后都需要一个
”;我会把它添加到我的答案中。
掩码可以写成
“\”“*3
谢谢--忘了那些,那些也更难“替换”回来。我看看以后是否能弄明白。我的观点是,这方面有很多边缘案例,我宁愿使用经过良好测试的库,也不愿使用我自己的库。你知道如何使用反射来取消景观吗?@Renkai你不需要反射。您可以使用StringContext:
StringContext.treatEscapes(res2)
。通过
StringContext保留双引号。treatEscapes
的作用正好相反:它将“\\t”转换为“\t”。@Renkai转换为unescape并删除双引号:
StringContext.treatEscapes(escapedString).drop(1).dropRight(1)
def escape(raw: String): String = {
  import scala.reflect.runtime.universe._
  Literal(Constant(raw)).toString
}
scala> "\bHallo" + '\n' + "\tWelt"
res1: String =
?Hallo
        Welt

scala> escape("\bHallo" + '\n' + "\tWelt")
res2: String = "\bHallo\n\tWelt"
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
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]