Raw Strings in Java - insbesondere für Regex. Mehrzeilige Zeichenfolgen

72

Gibt es eine Möglichkeit, rohe Zeichenfolgen in Java zu verwenden (ohne Escape-Sequenzen)?

(Ich schreibe eine ganze Menge Regex-Code und rohe Zeichenfolgen würden meinen Code immens lesbarer machen.)

Ich verstehe, dass die Sprache dies nicht direkt bereitstellt, aber gibt es eine Möglichkeit, sie auf irgendeine Weise zu "simulieren"?

PlagueHammer
quelle
5
Oh, das will ich so sehr. Auch mehrzeilige Zeichenfolgen. Und vielleicht einfache Interpolation.
Thilo
3
Obwohl Ihnen das nicht gefallen wird - ich denke, es fördert nur das Mischen Ihrer Daten mit Ihrem Code. Das Schönste an REGEXes ist, dass sie Daten sind und daher in eine indizierte Tabelle extrahiert werden können, was den gesamten Rest Ihres Codes vereinfacht. Änderungen an Ihren Informationen erfordern dann keine Neukompilierung. Lassen Sie Ihren Kunden lediglich Ihre REGEX-Quelldateien bearbeiten. Dies gilt für fast alles, wofür ich mehrzeilige Zeichenfolgen in Betracht ziehen würde. Immer besser extern (wenn nichts anderes, denken Sie an i18n!)
Bill K
ps. Als ich jung war, theoretisierte ein intelligenter Programmierer, dass die einzigen Konstanten in Ihrem Code 0 und 1 sein sollten und diejenigen, die nur als Schleifenbeendigungs- / Vergleichssituationen verwendet werden, die meistens nicht mehr gültig sind (wir können foreach anstelle von for (0 .. verwenden). )) Ich dachte, er wäre damals verrückt, aber je besser ich werde, desto schlauer klingt diese Theorie.
Bill K
Hinweis (Jan. 2018): Für Java (JDK 10 oder höher) werden möglicherweise unformatierte Zeichenfolgenliterale verwendet: Siehe Gibt es in Java eine Möglichkeit, ein Zeichenfolgenliteral zu schreiben, ohne Anführungszeichen zu umgehen? .
VonC
Die Situation ändert sich und die heutige Antwort, die als richtig markiert ist, ist falsch. Die richtige Antwort gibt Vlad. Über Textblöcke. Bitte erwägen Sie Änderungen, da diese Entscheidung die Menschen verwirrt.

Antworten:

4

Ja .

Textblöcke kommen nach Java

Java 13 liefert lang erwartete mehrzeilige Zeichenfolgen

Etwas Geschichte: Raw String Literals wurden zurückgezogen . Dies sollte eine Vorschau-Sprachfunktion in JDK 12 sein, wurde jedoch zurückgezogen und in JDK 12 nicht angezeigt. Sie wurde in JDK 13 durch Textblöcke (JEP 355) ersetzt.

Sie können Textblöcke verwenden, um mühelos mehrzeilige Zeichenfolgenliterale zu definieren. Sie müssen nicht die visuelle Unordnung hinzufügen, die mit regulären String-Literalen einhergeht: Verkettungsoperatoren und Escape-Sequenzen. Sie können auch steuern, wie die Zeichenfolgenwerte formatiert werden. Schauen wir uns zum Beispiel das folgende HTML-Snippet an:

String html = """
<HTML>
  <BODY>
    <H1>"Java 13 is here!"</H1>
  </BODY>
</HTML>""";

Beachten Sie die drei Anführungszeichen , die den Anfang und das Ende des Blocks begrenzen.

Vlad Novakovsky
quelle
48

Dies ist eine Problemumgehung, wenn Sie Eclipse verwenden. Sie können lange Textblöcke automatisch korrekt mehrzeilig und Sonderzeichen automatisch maskieren lassen, wenn Sie Text in ein Zeichenfolgenliteral einfügen

"-paste here-";

Wenn Sie diese Option in Fenster → Einstellungen → Java → Editor → Eingabe → "Escape-Text beim Einfügen in ein Zeichenfolgenliteral" aktivieren.

Fürchten
quelle
5
Das ist fantastisch. Ich wünschte, ich würde früher über diese Funktion Bescheid wissen!
Aglassman
1
Funktioniert auch in Netbeans.
Justin
39

Nein, gibt es nicht.

Im Allgemeinen würden Sie rohe Zeichenfolgen und reguläre Ausdrücke in eine Eigenschaftendatei einfügen, für diese gelten jedoch auch einige Anforderungen an die Escape-Sequenz.

Strohbraun
quelle
3
Siehe meine Antwort auf diese Frage. Es gibt jetzt einen Weg dafür. stackoverflow.com/a/16118875/1198772
ismailsunni
29

Ich benutze Pattern.quote . Und es löst das Problem der Frage. Also:

Pattern pattern = Pattern.compile(Pattern.quote("\r\n?|\n"));

Die Anführungszeichenmethode gibt eine Zeichenfolge zurück, die mit dem angegebenen Zeichenfolgenargument übereinstimmt. Die Rückgabezeichenfolge ist die in Anführungszeichen stehende Zeichenfolge für unseren Fall.

ismailsunni
quelle
4
Beachten Sie, dass dies nicht funktioniert, wenn die maskierten Zeichen keine gültigen Scape-Sequenzen für Java-String-Literale sind, sondern für reguläre Ausdrücke, zum Beispiel : "\.".
Ygormutti
6
Das ist klug, aber ... aaaaargh. Was für eine hackige Lösung für das, was in einer modernen Sprache kein Problem sein sollte. Ich bin mir nicht mal sicher, ob es sich lohnt, basierend auf Ygormuttis Beobachtung.
Kyle Strand
@KyleStrand Dies ist KEINE hackige Lösung. Pattern.quoteDies wäre auch dann erforderlich, wenn Java unformatierte Zeichenfolgenliterale hätte: Zeichen wie .und +erfordern keine spezielle Behandlung in Java-Zeichenfolgenliteralen, müssen jedoch für reguläre Ausdrücke maskiert werden. Python unterstützt rohe String-Literale, hat es aber immer noch re.escape.
Alex Shesterov
1
@AlexShesterov Escapezeichen in Regex sind weiterhin Teil des Regex-Ausdrucks , der an die Engine für reguläre Ausdrücke übergeben wird. Das heißt, die Regex-Engine erhält eine Literalsequenz \*. Das Fehlen von Rohzeichenfolgen in Java verbindet das Konzept der Erstellung eines Regex-Musters mit Sonderzeichen, die als Literale behandelt werden, und das Konzept der Erstellung von Zeichenfolgendaten mit Sonderzeichen. Dies sind separate Konzepte .
Kyle Strand
Jedenfalls löst dies mein Problem: Jetzt foo("\\[")kann man foo("[")glücklich sein.
Regen
13

Nein (ziemlich traurig).

jsight
quelle
1
Dies ist die erste Antwort auf SO, die ich gesehen habe, die so viele positive Stimmen erhalten hat, indem sie nur die Emotionen der Java-Programmierer ausnutzt xD
varun
4

Haben Sie die Rohtextdatei in Ihrem Klassenpfad und lesen Sie sie mit getResourceAsStream (....) ein.

Thorbjørn Ravn Andersen
quelle
4

( Eigenschaftendateien sind häufig, aber chaotisch - ich behandle die meisten regulären Ausdrücke als Code und behalte sie dort, wo ich darauf verweisen kann, und Sie sollten es auch. Was die eigentliche Frage betrifft :)

Ja, es gibt Möglichkeiten, die schlechte Lesbarkeit zu umgehen. Sie könnten versuchen:

String s = "crazy escaped garbage"; //readable version//

Dies erfordert jedoch Vorsicht beim Aktualisieren. Eclipse verfügt über eine Option, mit der Sie Text zwischen Anführungszeichen einfügen und die Escape-Sequenzen für Sie anwenden können. Die Taktik wäre, zuerst die lesbaren Versionen zu bearbeiten, dann den Müll zu löschen und sie zwischen die leeren Anführungszeichen "" einzufügen.


Ideenzeit:

Hacken Sie Ihren Editor, um sie zu konvertieren. als Plugin veröffentlichen. Ich habe nach Plugins gesucht, aber keine gefunden (versuchen Sie es trotzdem). Es gibt eine Eins-zu-Eins-Entsprechung zwischen maskierten Quellzeichenfolgen und Textfeldtext (Rabatt \ n, \ r \ n). Möglicherweise könnte hervorgehobener Text mit zwei Anführungszeichen an den Enden verwendet werden.

String s = "##########
#####";

Dabei ist # ein beliebiges Zeichen, das hervorgehoben ist. Die Unterbrechung wird als neue Zeile behandelt. Innerhalb des hervorgehobenen Bereichs eingegebener oder eingefügter Text wird in der "echten" Quelle maskiert und so angezeigt, als ob dies nicht der Fall wäre. (Auf die gleiche Weise, wie Eclipse eingefügten Text maskiert, wird typisierter Text maskiert und auch ohne umgekehrte Schrägstriche angezeigt.) Löschen Sie eines der Anführungszeichen, um einen Syntaxfehler zu verursachen, wenn Sie normal bearbeiten möchten. Hmm.

mk.
quelle
3

Hinweis: Ab heute nicht verfügbar. Wahrscheinlich werde ich diese Antwort bei jeder Veröffentlichung der Funktion erneut bearbeiten.

Es gibt einen laufenden Vorschlag zur Einführung von Raw Strings in Java . Sie sind tatsächlich sehr nützlich bei Regex.

Beispiel 1: Eine Zeichenfolge mit regulären Ausdrücken, die als codiert wurde

  System.out.println("this".matches("\\w\\w\\w\\w"));

kann alternativ als codiert werden

System.out.println("this".matches(`\w\w\w\w`));

da Backslashes nicht als besonders bedeutsam interpretiert werden.

Beispiel 2: Ein mehrzeiliges String-Literal mit Fremdsprache wird angehängt.

A multiple line string that was coded as 
    String html = "<html>\n" +
                "    <body>\n" +
                "         <p>Hello World.</p>\n" +
                "    </body>\n" +
                "</html>\n";

kann alternativ als codiert werden

 String html = `<html>
                       <body>
                           <p>Hello World.</p>
                       </body>
                   </html>
                  `;

Dadurch werden Zwischenzitate, Verkettungen und explizite Zeilenumbrüche vermieden.

Hoffentlich können wir die Veröffentlichung bald erwarten.

Suresh Atta
quelle
2
Es sieht so aus, als würde es dies in Java 12 schaffen: dzone.com/articles/…
JimmyJames
@ JimmyJames Hoffentlich wird Java 12 Mainstream sein, bevor die menschliche Zivilisation ausstirbt ... oder zumindest bevor Python 2 ausstirbt ..... -_-
varun
2

String # getBytes () macht eine Kopie des internen Byte-Arrays verfügbar, das in jedem einzelnen String-Objekt enthalten ist, das tatsächlich den 16-Bit-UTF-16-codierten String enthält. Das Byte-Array enthält denselben String, der so konvertiert wurde, dass er mit dem Standardzeichensatz der Plattform übereinstimmt. Was ich damit sagen will ist, dass ich denke, dass dies so nahe an der "rohen" Zeichenfolge liegt, wie Sie es jemals in Java bekommen können.

Esko
quelle
Sie sollten getBytes () mit dem charsetName verwenden, der String hat möglicherweise nicht die gleiche Codierung wie die Plattform
Rich Seller
Jede anständige IDE verfügt über einen Eigenschaftendatei-Editor, der alle bösen Fluchtversuche verarbeiten kann. ZB Elicpse
Thorbjørn Ravn Andersen
Rich Seller: Laut Javadocs sollte es mit dem Standard-Zeichensatz der Plattform übereinstimmen, aber ich wäre nicht überrascht, wenn dies nicht der Fall wäre.
Esko
1

Sie können Ihren eigenen, nicht maskierten Eigenschaftsleser schreiben und Ihre Zeichenfolgen in eine Ressourcendatei einfügen.

ShabbyDoo
quelle
1

Ich persönlich betrachte Regex-Strings als Daten und nicht als Code, daher mag ich sie in meinem Code nicht - aber mir ist klar, dass dies unpraktisch und unbeliebt ist (Ja, mir ist klar, dass Sie mich nicht anschreien müssen).

Da es keinen nativen Weg gibt, dies zu tun, kann ich mir zwei Möglichkeiten einfallen lassen (nun, drei, aber die dritte ist, ähm, unnatürlich).

Meine persönliche Präferenz wäre es also, eine Datei einfach in Strings zu analysieren. Sie können jeden Eintrag in der Datei benennen und alle in eine Hash-Tabelle laden, um von Ihrem Code aus leicht darauf zugreifen zu können.

Zweite Wahl: Erstellen Sie eine Datei, die in einer Java-Oberfläche vorverarbeitet wird. es könnte dabei der Regex entkommen. Persönlich hasse ich die Codegenerierung, aber wenn die Java-Datei zu 100% nie von Menschen bearbeitet wurde, ist sie nicht schlecht (das wahre Übel sind generierte Dateien, die Sie voraussichtlich bearbeiten werden!).

Drittens (knifflig und wahrscheinlich eine schlechte Idee): Möglicherweise können Sie ein benutzerdefiniertes Doclet erstellen, das beim Kompilieren Zeichenfolgen aus Ihren Kommentaren in eine Textdatei oder eine Headerdatei extrahiert, und dann eine der beiden oben genannten Methoden verwenden. Dadurch bleiben Ihre Zeichenfolgen in derselben Datei, in der sie verwendet werden. Dies könnte sehr schwer richtig zu machen sein, und die Strafen für Misserfolge sind extrem, so dass ich es nicht einmal in Betracht ziehen würde, wenn ich nicht ein überwältigendes Bedürfnis und ein ziemlich beeindruckendes Talent hätte.

Ich schlage dies nur vor, weil Kommentare frei formuliert sind und Dinge innerhalb eines "Pre" -Tags ziemlich sicher vor Formatierern und anderen hässlichen Systemen sind. Das Doclet könnte dies extrahieren, bevor die Javadocs gedruckt werden, und sogar einige der generierten Javadocs hinzufügen, die auf Ihre Verwendung von Regex-Zeichenfolgen hinweisen.

Bevor ich abstimme und mir sage, dass dies eine dumme Idee ist - ich weiß, ich dachte nur, ich würde es vorschlagen, weil es interessant ist, aber meine Präferenz, wie ich oben sagte, ist eine einfache Textdatei ...

Bill K.
quelle
5
Die meisten Regexs, die ich gesehen habe, sind definitiv ein wesentlicher Bestandteil des Programms, das sie verwendet, und sollten nicht als Daten angesehen werden. Sie möchten sie nicht mehr oder weniger als jede andere Logik darin externalisieren, z. B. Bedingungen in if-Anweisungen.
Thilo
Tatsächlich sind die Externalisierungsbedingungen oft auch gut, das ist eine Menge, was hinter Schließungen steckt. Sind reguläre Ausdrücke normalerweise nicht an externe Daten gebunden? Wenn ja, möchten Sie sie auf jeden Fall ändern können. Ich denke, der Punkt ist, dass Sie alles, was Sie können, externalisieren sollten, und der große Vorteil von Regex ist, dass Sie es können.
Bill K
1
Ich bin mit Thilo dabei. Regexes definieren normalerweise die Art des datenspezifischen Codes, nach dem diese Daten gesucht oder analysiert werden. Wenn Sie es externalisieren, ist es für jemanden leicht, dies zu ändern, ohne die Auswirkungen zu erkennen.
Kevin Brock
0

Nein. Es gibt jedoch ein IntelliJ-Plug-In namens String Manipulation , mit dem dies einfacher zu handhaben ist .

IntelliJ entkommt auch automatisch einem eingefügten String. (Wie @Dread hervorhebt , verfügt Eclipse über ein Plug-In, um dies zu ermöglichen.)

Michael Scheper
quelle