2009-05-07 4 views
1

Kann jemand eine Zeichenkette auf einem Zeichen unter Berücksichtigung seiner Escape-Sequenz teilen?Teilen einer Zeichenkette (besonders in Java mit java.util.regex oder etwas anderem)

Wenn das Zeichen beispielsweise ":" ist, wird "a: b" in zwei Teile ("a" und "b") aufgeteilt, während "a: b" überhaupt nicht geteilt wird.

Ich denke, das ist schwer (unmöglich?) Mit regulären Ausdrücken zu tun.

Vielen Dank im Voraus,

Kedar

+0

Siehe auch http://stackoverflow.com/questions/820172/how-to-split-a-comma-separated-string-while-ignoring-escaped-commas. –

Antwort

2

(?<=^|[^\\]): bekommt man schließen, aber geht nicht entgangen Schrägstriche. (Das ist ein Literal Regex, natürlich müssen Sie die Schrägstriche darin entkommen, um es in eine Java-Zeichenfolge zu bekommen)

(?<=(^|[^\\])(\\\\)*): Wie wäre es damit? Ich denke, das sollte jedem ':' genügen, dem eine gerade Anzahl von Schrägstrichen vorausgeht.

Edit: nicht stimmen. MizardX Lösung ist besser :)

+0

Der Schlüssel ist das (? <= Foo) Konstrukt, positiver Look-Behind. Sie müssen prüfen, was vor dem ':' steht, ohne es zu vergleichen. –

+1

MizardX weist darauf hin, dass Look-Behind eine endliche Länge haben muss. Meins ist nicht so, ich denke, es würde nicht funktionieren (nicht getestet). Ich glaube unsere Lösungen sind ansonsten ähnlich. Es ist wahrscheinlich besser, dass es negatives Look-Behind verwendet, um nach einem Schrägstrich-Zeichen zu suchen, während ich "^ | [^ \\\]" verwende, das in mehrzeiligen Szenarios unterschiedlich sein kann oder nicht (nicht sicher). . –

+1

(^ | [^ \\\]) sollte funktionieren.^könnte möglicherweise den Anfang einer Zeile anstelle einer Zeichenfolge entsprechen. Das ist in Ordnung, da es immer noch sicherstellt, dass es kein Backslash ist. [^ \\\] wird auch mit Zeilenumbrüchen übereinstimmen, also kein Problem, wenn auch der Mehrzeilenmodus nicht verwendet wird. –

2

Da Java variabler Länge Look-behinds unterstützt (solange sie endlich sind), können Sie es tun, wie folgt tun:

import java.util.regex.*; 

public class RegexTest { 
    public static void main(String[] argv) { 

     Pattern p = Pattern.compile("(?<=(?<!\\\\)(?:\\\\\\\\){0,10}):"); 

     String text = "foo:bar\\:baz\\\\:qux\\\\\\:quux\\\\\\\\:corge"; 

     String[] parts = p.split(text); 

     System.out.printf("Input string: %s\n", text); 
     for (int i = 0; i < parts.length; i++) { 
      System.out.printf("Part %d: %s\n", i+1, parts[i]); 
     } 

    } 
} 
  • (?<=(?<!\\)(?:\\\\){0,10}) für ein hinter aussieht gerade Anzahl von Backslashes (einschließlich Null, bis zu einem Maximum von 10).

Ausgang:

Input string: foo:bar\:baz\\:qux\\\:quux\\\\:corge
Part 1: foo
Part 2: bar\:baz\\
Part 3: qux\\\:quux\\\\
Part 4: corge

Eine andere Möglichkeit wäre es, die Teile selbst anzupassen, statt Spaltung an den Begrenzer.

Die seltsame Syntax ergibt sich daraus, dass es den Fall von leeren Stücken am Anfang und Ende der Zeichenfolge behandeln muss. Wenn eine Übereinstimmung genau null Zeichen umfasst, beginnt der nächste Versuch ein Zeichen nach dem Ende davon. Wenn nicht, würde es zu einer anderen leeren Zeichenfolge passen, und eine andere, ad infinitum & hellip;

  • (?<=\A|\G:) wird entweder für den Start des Strings Blick hinter (das erste Stück) oder das Ende des vorherigen Spiels, durch den Separator, gefolgt. Wenn wir (?:\A|\G:) hätten, würde es fehlschlagen, wenn das erste Stück leer ist (die Eingabe beginnt mit einem Trennzeichen).
  • \\. passt auf alle maskierten Zeichen.
  • [^:\\] passt auf ein beliebiges Zeichen, das nicht in einer Escape-Sequenz enthalten ist (weil \\. beides verbraucht hat).
  • ((?:\\.|[^:\\])*) erfasst alle Zeichen bis zum ersten Nicht-Escape-Begrenzer in Fanggruppe 1.
Verwandte Themen