2012-03-28 17 views
22

Básicamente, lo que me gustaría hacer es tener:Scala: ¿Cómo puedo obtener una representación escapada de una cadena?

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

hacer esto:

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

Básicamente busca de un análogo de String#inspect de rubí o Haskell de show :: String -> String.

Respuesta

18

Esta pregunta es un poco viejo, pero tropecé con él durante la búsqueda de una solución a mí mismo y estaba insatisfecho con las otras respuestas porque no son seguras (reemplazando cosas por su cuenta) o requieren una biblioteca externa.

Encontré una forma de obtener la representación escapada de una cadena con la biblioteca estándar scala (> 2.10.0) que es segura. Utiliza un pequeño truco:

A través de la reflexión en tiempo de ejecución puede obtener fácilmente una representación de una expresión de cadena literal. El árbol de dicha expresión se devuelve como (casi) código scala al llamar al método toString. Esto significa especialmente que el literal se representa de la forma en que sería en código, es decir, escapado y comillas dobles.

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

Por tanto, la función de escape se traduce en el código de representación deseada de la cadena de texto proporcionado (incluyendo las comillas dobles que rodean):

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

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

Esta solución está abusando cierto que el API de reflexión, pero en mi humilde opinión aún más seguro y más sostenible que las otras soluciones propuestas.

+0

¿Sabes cómo separar el uso con la reflexión? – Renkai

+1

@Renkai no necesita reflexión para esto. Puede usar StringContext: 'StringContext.treatEscapes (res2)'. Deja las comillas dobles aunque –

+1

'StringContext.treatEscapes' hace lo contrario: convierte" \\ t "en" \ t ". –

2

Si Compilo siguientes:

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

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

no encuentro una diferencia en la cadena, así que supongo que: No hay posibilidad, para averiguar, si hubo un "\ n" en la fuente.

¿Pero tal vez te equivoqué y quisieras obtener el mismo resultado para ambos?

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

La segunda posibilidad es:

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

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

prueba:

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""" 
+0

(U) Estoy buscando a una función que se escapa una cadena, donde escapar una cadena implica la transformación de todos los "\ n" a "\\ n" "\ t" a "\ \ t ", etc., y posiblemente adjunte el resultado entre comillas dobles (dependiendo del idioma). – rampion

+0

En la compilación, al menos \ n se transforma en 0A (si observas a través de un editor hexadecimal). Apuesto a que verás un equivalente para \ t, lo mismo que si hubieras usado una pestaña con la tecla Tab. De acuerdo, necesitas un '" 'antes y detrás de String; lo agregaré a mi respuesta. –

+0

' mask' se puede escribir como '" \ "" * 3' – sschaef

19

Estoy bastante seguro de que esto no está disponible en las librerías estándar, ya sea para Scala o Java, pero está en 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 

Puede agregar fácilmente las comillas a la cadena escapada si lo desea, por supuesto.

2

Se puede construir su propia función con bastante facilidad, si no desea utilizar la biblioteca 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 \\ 
+0

no te olvides de los ascii no imprimibles, y unicode ... – rampion

+0

Gracias - se olvidó de aquellos, esos son más difíciles de simplemente "reemplazar", también. Veré si puedo resolverlo más tarde. –

+2

mi punto es que hay MUCHOS casos extremos con esto, y prefiero usar una biblioteca bien probada que la propia. – rampion

5

La solución scala.reflect realmente funciona bien. Cuando no quiere obtener toda la biblioteca, esto es lo que parece hacer bajo el capó (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 
Cuestiones relacionadas