2012-03-28 5 views
22

Im Grunde, was ich möchte zu tun haben:Scala: Wie kann ich eine Escape-Darstellung einer Zeichenfolge erhalten?

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

tun:

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

Grundsätzlich für ein Analogon von Rubys String#inspect oder Haskells show :: String -> String suchen.

Antwort

18

Diese Frage ist ein bisschen alt, aber ich stolperte über sie, während für eine Lösung selbst suchen und war mit den anderen Antworten unzufrieden, weil sie entweder nicht sicher sind (sie selbst ersetzen) oder eine externe Bibliothek benötigen.

Ich habe einen Weg gefunden, um die Escape-Darstellung einer Zeichenfolge mit der Scala-Standardbibliothek (> 2.10.0) zu bekommen, die sicher ist. Es verwendet einen kleinen Trick:

Durch Laufzeit-Reflektion können Sie leicht eine Darstellung eines literalen String-Ausdrucks erhalten. Der Baum eines solchen Ausdrucks wird beim Aufruf seiner Methode toString als (fast) Scala-Code zurückgegeben. Dies bedeutet insbesondere, dass das Literal so dargestellt wird, wie es im Code wäre, d. H. Maskiert und doppelt zitiert.

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

Die escape Funktion ergibt sich somit in der gewünschten Code-Darstellung der rohen Saite (einschließlich der umgebenden doppelte Anführungszeichen):

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

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

Diese Lösung zwar die Reflexion api aber IMHO mißbraucht noch sicherer und wartbarer als die anderen vorgeschlagenen Lösungen.

+0

Wissen Sie, wie man mit Reflektion unescape verwendet? – Renkai

+1

@Renkai Sie brauchen keine Reflexion dafür. Sie können StringContext verwenden: 'StringContext.treatEscapes (res2)'. Verlässt die Anführungszeichen jedoch –

+1

? StringContext.treatEscapes' tut das Gegenteil: es wandelt "\\ t" in "\ t" um. –

2

Wenn ich kompilieren diese:

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

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

ich, keinen Unterschied in der String finden also denke ich: Es gibt keine Möglichkeit ist, um herauszufinden, ob es ein „\ n“ war in die Quelle.

Aber vielleicht habe ich dich falsch verstanden, und Sie möchten das gleiche Ergebnis für beide bekommen?

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

Die zweite Möglichkeit ist:

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

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

Test:

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) Ich suche nach einer Funktion, die einen String entkommt, in dem eine Zeichenfolge entweichenden bezieht alle "\ n" Umwandlung zu "\\ n", "\ t" auf „\ \ t ", etc, und möglicherweise das Ergebnis in doppelte Anführungszeichen einschließen (abhängig von der Sprache). – rampion

+0

Bei der Kompilierung wird mindestens \ n in eine 0A umgewandelt (wenn Sie zufällig einen Hexeditor durchsehen). Ich wette, Sie werden eine Entsprechung für \ t sehen - genauso, als ob Sie einen Tab mit der Tab-Taste benutzt hätten. Okay - du brauchst ein '' 'vor und hinter dem String; ich füge es meiner Antwort hinzu. –

+0

' mask' kann geschrieben werden als '" \ "" * 3' – sschaef

19

Ich bin ziemlich sicher, das entweder für Scala oder Java in den Standardbibliotheken nicht verfügbar ist, aber es ist in 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 

Sie könnten natürlich die Anführungszeichen zur Escapezeichenfolge hinzufügen, wenn Sie möchten.

2

Sie könnten Ihre eigene Funktion ziemlich leicht bauen, wenn Sie die Apache-Bibliothek nicht verwenden wollen:

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

nicht nicht druckbare ASCII, und vergessen Unicode ... – rampion

+0

Danke - vergaß diese, die sind kniffliger, nur "ersetzen" zurück, auch. Ich werde sehen, ob ich es später herausfinden kann. –

+2

mein Punkt ist, dass es eine Menge von Rand Fällen mit diesem ist, und ich lieber eine gut getestete Bibliothek als meine eigenen rollen würde. – rampion

5

Die scala.reflect Lösung funktioniert tatsächlich gut. Wenn du diese ganze Bibliothek nicht reinziehen willst, scheint das unter der Haube zu funktionieren (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 
Verwandte Themen