Ich habe eine mehrzeilige Zeichenfolge, die durch eine Reihe verschiedener Trennzeichen begrenzt ist:
(Text1)(DelimiterA)(Text2)(DelimiterC)(Text3)(DelimiterB)(Text4)
Ich kann diese Zeichenfolge mithilfe von in ihre Teile aufteilen String.split
, aber es scheint, dass ich die tatsächliche Zeichenfolge, die mit dem Regex des Trennzeichens übereinstimmt, nicht erhalten kann.
Mit anderen Worten, das bekomme ich:
Text1
Text2
Text3
Text4
Das ist was ich will
Text1
DelimiterA
Text2
DelimiterC
Text3
DelimiterB
Text4
Gibt es eine JDK-Möglichkeit, die Zeichenfolge mithilfe eines Trennzeichen-Regex zu teilen, aber auch die Trennzeichen beizubehalten?
Antworten:
Sie können Lookahead und Lookbehind verwenden. So was:
Und du wirst bekommen:
Der letzte ist was du willst.
((?<=;)|(?=;))
entspricht der Auswahl eines leeren Zeichens vor;
oder nach;
.Hoffe das hilft.
BEARBEITEN Fabian Steeg Kommentare zur Lesbarkeit sind gültig. Die Lesbarkeit ist für RegEx immer das Problem. Eine Sache, die ich mache, um dies zu vereinfachen, besteht darin, eine Variable zu erstellen, deren Name die Funktion des regulären Ausdrucks darstellt, und das Java-String-Format zu verwenden, um dies zu unterstützen. So was:
Das hilft ein bisschen. :-D
quelle
split(";", true)
wäre so viel besser lesbar alssplit("((?<=;)|(?=;))")
.String.format(WITH_DELIMITER, ";");
as Format ist eine statische Methode.[\\s,]+
), die Sie vollständig anpassen möchten. Die erforderlichen regulären Ausdrücke werden noch länger, da Sie zusätzliche negative Blicke benötigen, um zu vermeiden, dass sie in der Mitte übereinstimmen, z.(?<=[\\s,]+)(?![\\s,])|(?<![\\s,])(?=[\\s,]+)
.Sie möchten Lookarounds verwenden und auf Übereinstimmungen mit der Breite Null aufteilen. Hier sind einige Beispiele:
Und ja, das ist eine dreifach verschachtelte Behauptung im letzten Muster.
Verwandte Fragen
Siehe auch
quelle
Eine sehr naive Lösung, bei der kein regulärer Ausdruck erforderlich ist, besteht darin, eine Zeichenfolge an Ihrem Trennzeichen zu ersetzen (unter der Annahme von Komma für Trennzeichen):
Hier können Sie tilda (~) durch ein geeignetes eindeutiges Trennzeichen ersetzen.
Wenn Sie dann einen Split für Ihr neues Trennzeichen vornehmen, werden Sie meiner Meinung nach das gewünschte Ergebnis erzielen.
quelle
Ich mag den anderen Weg nicht wirklich, wo man vorne und hinten ein leeres Element bekommt. Ein Trennzeichen befindet sich normalerweise nicht am Anfang oder am Ende der Zeichenfolge. Daher verschwenden Sie am häufigsten zwei gute Array-Slots.
Bearbeiten: Feste Grenzfälle. Eine kommentierte Quelle mit Testfällen finden Sie hier: http://snippets.dzone.com/posts/show/6453
quelle
null
ist es der richtige Weg , NPE auf Argumente zu werfen . Wenn Sie es stillschweigend behandeln, werden später Fehler angezeigt.Ich bin spät hier angekommen, aber zurück zur ursprünglichen Frage, warum nicht einfach Lookarounds verwenden?
Ausgabe:
BEARBEITEN: Was Sie oben sehen, wird in der Befehlszeile angezeigt, wenn ich diesen Code ausführe, aber jetzt sehe ich, dass es etwas verwirrend ist. Es ist schwierig zu verfolgen, welche Kommas Teil des Ergebnisses sind und welche von hinzugefügt wurden
Arrays.toString()
. Die Syntaxhervorhebung von SO hilft auch nicht. In der Hoffnung, dass die Hervorhebung mit mir anstatt gegen mich funktioniert, würden diese Arrays folgendermaßen aussehen: Ich habe sie im Quellcode deklariert:Ich hoffe das ist leichter zu lesen. Danke für das Heads-up, @finnw.
quelle
Ich weiß, dass dies eine sehr, sehr alte Frage ist und die Antwort auch akzeptiert wurde. Trotzdem möchte ich eine sehr einfache Antwort auf die ursprüngliche Frage geben. Betrachten Sie diesen Code:
AUSGABE:
Ich benutze nur die Wortgrenze
\b
, um die Wörter abzugrenzen, außer wenn es sich um einen Textanfang handelt.quelle
abcdef
mitde
als Trennzeichen, aber Sie können das Problem mit lösen(?!^|$)(?:(?<=de)(?!de)|(?<!de)(?=de))
(?!^|$)
Ich habe mir die obigen Antworten angesehen und ehrlich gesagt finde ich keine zufriedenstellend. Was Sie tun möchten, ist im Wesentlichen die Perl-Split-Funktionalität nachzuahmen. Warum Java dies nicht zulässt und irgendwo eine join () -Methode hat, ist mir ein Rätsel, aber ich schweife ab. Sie brauchen dafür nicht einmal eine Klasse. Es ist nur eine Funktion. Führen Sie dieses Beispielprogramm aus:
Einige der früheren Antworten haben eine übermäßige Nullprüfung, die ich kürzlich hier auf eine Frage beantwortet habe:
https://stackoverflow.com/users/18393/cletus
Wie auch immer, der Code:
quelle
Ich mag die Idee von StringTokenizer, weil es Enumerable ist.
Es ist aber auch veraltet und wird durch String.split ersetzt, das einen langweiligen String [] zurückgibt (und die Trennzeichen nicht enthält).
Also habe ich einen StringTokenizerEx implementiert, der ein Iterable ist und der einen echten regulären Ausdruck benötigt, um einen String zu teilen.
Ein wahrer regulärer Ausdruck bedeutet, dass es sich nicht um eine 'Zeichenfolge' handelt, die wiederholt wird, um das Trennzeichen zu bilden:
'o' stimmt nur mit 'o' überein und teilt 'ooo' in drei Trennzeichen mit zwei leeren Zeichenfolgen auf:
Der reguläre Ausdruck o + gibt jedoch das erwartete Ergebnis zurück, wenn "aooob" aufgeteilt wird.
So verwenden Sie diesen StringTokenizerEx:
Der Code dieser Klasse ist bei DZone Snippets verfügbar .
Kopieren Sie sie wie üblich für eine Code-Challenge- Antwort (eine in sich geschlossene Klasse mit Testfällen), fügen Sie sie ein (in ein 'src / test'-Verzeichnis) und führen Sie sie aus . Die main () -Methode veranschaulicht die verschiedenen Verwendungen.
Hinweis: (Ende 2009 bearbeiten)
Der Artikel Final Thoughts: Java Puzzler: Splitting Hairs leistet eine gute Arbeit, um das bizarre Verhalten in zu erklären
String.split()
.Josh Bloch antwortete sogar auf diesen Artikel:
Die Google Common-Library Guava enthält auch einen Splitter:
Es kann sich also lohnen, ausgecheckt zu werden. Aus ihrer anfänglichen groben Dokumentation (pdf) :
quelle
Übergeben Sie das 3. Dokument als "wahr". Es werden auch Trennzeichen zurückgegeben.
quelle
Hier ist eine einfache, saubere Implementierung, die mit
Pattern#split
Mustern variabler Länge konsistent ist und mit diesen funktioniert, die hinterher nicht unterstützt werden können, und die einfacher zu verwenden ist. Es ähnelt der von @cletus bereitgestellten Lösung.Ich mache hier keine Nullprüfungen,
Pattern#split
nicht, warum sollte ich. Ich mag dasif
am Ende nicht, aber es ist für die Konsistenz mit dem erforderlichPattern#split
. Andernfalls würde ich bedingungslos anhängen, was zu einer leeren Zeichenfolge als letztes Element des Ergebnisses führt, wenn die Eingabezeichenfolge mit dem Muster endet.Ich konvertiere in String [], um die Konsistenz mit zu gewährleisten.
Pattern#split
Ich verwendenew String[0]
eher alsnew String[result.size()]
, siehe hier, warum.Hier sind meine Tests:
quelle
Ich werde auch meine Arbeitsversionen veröffentlichen (erstens ist Markus wirklich ähnlich).
Und hier ist die zweite Lösung und ihre Runde 50% schneller als die erste:
quelle
Eine weitere mögliche Lösung mit einem regulären Ausdruck. Behält die Token-Reihenfolge bei und stimmt korrekt mit mehreren Token desselben Typs hintereinander überein. Der Nachteil ist, dass der Regex irgendwie böse ist.
Beispielausgabe:
quelle
Ich kenne keine vorhandene Funktion in der Java-API, die dies ausführt (was nicht heißt, dass sie nicht vorhanden ist), aber hier ist meine eigene Implementierung (ein oder mehrere Trennzeichen werden als einzelnes Token zurückgegeben, wenn Sie möchten Jedes Trennzeichen, das als separates Token zurückgegeben werden soll, muss angepasst werden.
quelle
Ich schlage vor, Pattern und Matcher zu verwenden, um mit ziemlicher Sicherheit das zu erreichen, was Sie wollen. Ihr regulärer Ausdruck muss etwas komplizierter sein als das, was Sie in String.split verwenden.
quelle
Ich denke nicht, dass dies mit möglich ist
String#split
, aber Sie können a verwendenStringTokenizer
, obwohl Sie damit Ihr Trennzeichen nicht als regulären Ausdruck definieren können, sondern nur als Klasse einstelliger Zeichen:quelle
Wenn Sie es sich leisten können, verwenden Sie die Java-Ersetzungsmethode (CharSequence-Ziel, CharSequence-Ersetzung) und geben Sie ein anderes Trennzeichen ein, mit dem Sie teilen möchten. Beispiel: Ich möchte die Zeichenfolge "boo: and: foo" teilen und ':' an der rechten Zeichenfolge belassen.
Wichtiger Hinweis: Dies funktioniert nur, wenn Sie keinen weiteren "newdelimiter" in Ihrem String haben! Somit ist es keine allgemeine Lösung. Wenn Sie jedoch eine CharSequence kennen, von der Sie sicher sein können, dass sie niemals in der Zeichenfolge angezeigt wird, ist dies eine sehr einfache Lösung.
quelle
Schnelle Antwort: Verwenden Sie zum Teilen nicht physische Grenzen wie \ b. Ich werde versuchen zu experimentieren, um zu sehen, ob es funktioniert (verwendet das in PHP und JS).
Es ist möglich und Art der Arbeit, könnte aber zu viel spalten. Tatsächlich hängt es von der Zeichenfolge ab, die Sie teilen möchten, und vom Ergebnis, das Sie benötigen. Geben Sie weitere Details an, wir helfen Ihnen besser.
Eine andere Möglichkeit besteht darin, eine eigene Aufteilung vorzunehmen, das Trennzeichen zu erfassen (vorausgesetzt, es ist variabel) und es anschließend zum Ergebnis hinzuzufügen.
Mein schneller Test:
Ergebnis:
Ein bisschen zu viel... :-)
quelle
Gezwickt Pattern.split () auf abgestimmte Muster auf der Liste umfassen
Hinzugefügt
Vollständige Quelle
quelle
Hier ist eine groovige Version, die auf dem obigen Code basiert, falls es hilft. Es ist sowieso kurz. Beinhaltet bedingt den Kopf und den Schwanz (wenn sie nicht leer sind). Der letzte Teil ist ein Demo / Testfall.
quelle
Eine äußerst naive und ineffiziente Lösung, die dennoch funktioniert. Verwenden Sie die Aufteilung zweimal auf die Zeichenfolge und verketten Sie dann die beiden Arrays
quelle
quelle
Scanner scanner = new Scanner("((A+B)*C-D)*E"); scanner.useDelimiter("((?<=[\\+\\*\\-\\/\\(\\)])|(?=[\\+\\*\\-\\/\\(\\)]))"); while (scanner.hasNext()) { System.out.print(" " + scanner.next()); }
Eine der Feinheiten in dieser Frage betrifft die Frage "führendes Trennzeichen": Wenn Sie ein kombiniertes Array von Token und Trennzeichen haben möchten, müssen Sie wissen, ob es mit einem Token oder einem Trennzeichen beginnt. Sie könnten natürlich einfach davon ausgehen, dass ein führendes Delim verworfen werden sollte, aber dies scheint eine ungerechtfertigte Annahme zu sein. Vielleicht möchten Sie auch wissen, ob Sie ein nachfolgendes Delim haben oder nicht. Dies setzt zwei boolesche Flags entsprechend.
Geschrieben in Groovy, aber eine Java-Version sollte ziemlich offensichtlich sein:
quelle
Ich kenne Java nicht so gut, aber wenn Sie keine Split-Methode finden, die das macht, schlage ich vor, Sie machen einfach Ihre eigene.
Es ist nicht zu elegant, aber es wird reichen.
quelle