Come dividere una stringa, ma anche mantenere i delimitatori?

Ho una stringa multilinea che è delimitata da un insieme di delimitatori diversi:

(Text1)(DelimiterA)(Text2)(DelimiterC)(Text3)(DelimiterB)(Text4) 

Posso dividere questa stringa nelle sue parti, usando String.split , ma sembra che non riesca a ottenere la stringa vera e propria, che corrisponde alla regex del delimitatore.

In altre parole, questo è ciò che ottengo:

  • Text1
  • Text2
  • Text3
  • Text4

Questo è quello che voglio

  • Text1
  • DelimiterA
  • Text2
  • DelimiterC
  • Text3
  • DelimiterB
  • Text4

C’è un modo JDK per dividere la stringa usando una regex del delimitatore ma anche mantenere i delimitatori?

Puoi usare Lookahead e Lookbehind. Come questo:

 System.out.println(Arrays.toString("a;b;c;d".split("(?< =;)"))); System.out.println(Arrays.toString("a;b;c;d".split("(?=;)"))); System.out.println(Arrays.toString("a;b;c;d".split("((?<=;)|(?=;))"))); 

E otterrai:

 [a;, b;, c;, d] [a, ;b, ;c, ;d] [a, ;, b, ;, c, ;, d] 

L'ultimo è quello che vuoi.

((?< =;)|(?=;)) equivale a selezionare un carattere vuoto prima ; o dopo ; .

Spero che questo ti aiuti.

EDIT Fabian Steeg commenta che Readability è valido. La leggibilità è sempre il problema per RegEx. Una cosa, per aiutare a facilitare questo è quello di creare una variabile il cui nome rappresenta ciò che fa la regex e utilizzare il formato di stringa Java per aiutarlo. Come questo:

 static public final String WITH_DELIMITER = "((?< =%1$s)|(?=%1$s))" ; ... public void someMethod() { ... final String[] aEach = "a;b;c;d". split(String.format(WITH_DELIMITER, ";")) ; ... } ... 

Questo aiuta un po '. 😀

Si desidera utilizzare i lookaround e dividere le corrispondenze con larghezza zero. Ecco alcuni esempi:

 public class SplitNDump { static void dump(String[] arr) { for (String s : arr) { System.out.format("[%s]", s); } System.out.println(); } public static void main(String[] args) { dump("1,234,567,890".split(",")); // "[1][234][567][890]" dump("1,234,567,890".split("(?=,)")); // "[1][,234][,567][,890]" dump("1,234,567,890".split("(?< =,)")); // "[1,][234,][567,][890]" dump("1,234,567,890".split("(?<=,)|(?=,)")); // "[1][,][234][,][567][,][890]" dump(":a:bb::c:".split("(?=:)|(?<=:)")); // "[][:][a][:][bb][:][:][c][:]" dump(":a:bb::c:".split("(?=(?!^):)|(?<=:)")); // "[:][a][:][bb][:][:][c][:]" dump(":::a::::bb::c:".split("(?=(?!^):)(? 

E sì, questa è l'asserzione tripartita lì nell'ultimo schema.

Domande correlate

  • Java split sta mangiando i miei personaggi.
  • Puoi usare regex di corrispondenza a larghezza zero in String split?
  • Come posso convertire CamelCase in nomi leggibili dall'uomo in Java?
  • Backreferences in lookbehind

Guarda anche

  • regular-expressions.info/Lookarounds

Una soluzione molto ingenua, che non prevede regex, è quella di eseguire una sostituzione di stringa sul delimitatore lungo le linee di (assumendo la virgola per il delimitatore):

 string.replace(FullString, "," , "~,~") 

Dove è ansible sostituire tilda (~) con un delimitatore univoco appropriato.

Quindi se fai una divisione sul tuo nuovo delimitatore, allora credo che otterrai il risultato desiderato.

 import java.util.regex.*; import java.util.LinkedList; public class Splitter { private static final Pattern DEFAULT_PATTERN = Pattern.compile("\\s+"); private Pattern pattern; private boolean keep_delimiters; public Splitter(Pattern pattern, boolean keep_delimiters) { this.pattern = pattern; this.keep_delimiters = keep_delimiters; } public Splitter(String pattern, boolean keep_delimiters) { this(Pattern.compile(pattern==null?"":pattern), keep_delimiters); } public Splitter(Pattern pattern) { this(pattern, true); } public Splitter(String pattern) { this(pattern, true); } public Splitter(boolean keep_delimiters) { this(DEFAULT_PATTERN, keep_delimiters); } public Splitter() { this(DEFAULT_PATTERN); } public String[] split(String text) { if (text == null) { text = ""; } int last_match = 0; LinkedList splitted = new LinkedList(); Matcher m = this.pattern.matcher(text); while (m.find()) { splitted.add(text.substring(last_match,m.start())); if (this.keep_delimiters) { splitted.add(m.group()); } last_match = m.end(); } splitted.add(text.substring(last_match)); return splitted.toArray(new String[splitted.size()]); } public static void main(String[] argv) { if (argv.length != 2) { System.err.println("Syntax: java Splitter  "); return; } Pattern pattern = null; try { pattern = Pattern.compile(argv[0]); } catch (PatternSyntaxException e) { System.err.println(e); return; } Splitter splitter = new Splitter(pattern); String text = argv[1]; int counter = 1; for (String part : splitter.split(text)) { System.out.printf("Part %d: \"%s\"\n", counter++, part); } } } /* Example: > java Splitter "\W+" "Hello World!" Part 1: "Hello" Part 2: " " Part 3: "World" Part 4: "!" Part 5: "" */ 

Non mi piace molto dall’altra parte, dove ottieni un elemento vuoto davanti e dietro. Un delimitatore di solito non si trova all’inizio o alla fine della stringa, quindi si finisce per sprecare due slot di array.

Modifica: casi limite fissi. La fonte commentata con i casi di test può essere trovata qui: http://snippets.dzone.com/posts/show/6453

Sono arrivato tardi, ma tornando alla domanda iniziale, perché non usare solo lookaround?

 Pattern p = Pattern.compile("(?< =\\w)(?=\\W)|(?<=\\W)(?=\\w)"); System.out.println(Arrays.toString(p.split("'ab','cd','eg'"))); System.out.println(Arrays.toString(p.split("boo:and:foo"))); 

produzione:

 [', ab, ',', cd, ',', eg, '] [boo, :, and, :, foo] 

EDIT: Quello che vedi sopra è ciò che appare sulla riga di comando quando eseguo quel codice, ma ora vedo che è un po 'di confusione. È difficile tenere traccia di quali virgole fanno parte del risultato e quali sono state aggiunte da Arrays.toString() . L'evidenziazione della syntax di SO non aiuta neanche. Nella speranza che l'evidenziazione funzioni con me invece che contro di me, ecco come appariranno quegli array che li stavo dichiarando nel codice sorgente:

 { "'", "ab", "','", "cd", "','", "eg", "'" } { "boo", ":", "and", ":", "foo" } 

Spero sia più facile da leggere. Grazie per l'heads-up, @finnw.

So che questa è una domanda molto vecchia e anche la risposta è stata accettata. Ma vorrei comunque presentare una risposta molto semplice alla domanda originale. Considera questo codice:

 String str = "Hello-World:How\nAre You&doing"; inputs = str.split("(?!^)\\b"); for (int i=0; i 

PRODUZIONE:

 a[0] = "Hello" a[1] = "-" a[2] = "World" a[3] = ":" a[4] = "How" a[5] = " " a[6] = "Are" a[7] = " " a[8] = "You" a[9] = "&" a[10] = "doing" 

Sto solo usando il limite della parola \b per delimitare le parole tranne quando è l'inizio del testo.

Ho dato un’occhiata alle risposte di cui sopra e onestamente nessuno di loro trovo soddisfacente. Quello che vuoi fare è essenzialmente imitare la funzionalità split di Perl. Perché Java non consente questo e ha un metodo join () da qualche parte è oltre me ma sto divagando. Non hai nemmeno bisogno di una lezione per questo davvero. È solo una funzione. Esegui questo esempio di programma:

Alcune delle risposte precedenti hanno un controllo eccessivo, che di recente ho scritto una risposta a una domanda qui:

https://stackoverflow.com/users/18393/cletus

Ad ogni modo, il codice:

 public class Split { public static List split(String s, String pattern) { assert s != null; assert pattern != null; return split(s, Pattern.compile(pattern)); } public static List split(String s, Pattern pattern) { assert s != null; assert pattern != null; Matcher m = pattern.matcher(s); List ret = new ArrayList(); int start = 0; while (m.find()) { ret.add(s.substring(start, m.start())); ret.add(m.group()); start = m.end(); } ret.add(start >= s.length() ? "" : s.substring(start)); return ret; } private static void testSplit(String s, String pattern) { System.out.printf("Splitting '%s' with pattern '%s'%n", s, pattern); List tokens = split(s, pattern); System.out.printf("Found %d matches%n", tokens.size()); int i = 0; for (String token : tokens) { System.out.printf(" %d/%d: '%s'%n", ++i, tokens.size(), token); } System.out.println(); } public static void main(String args[]) { testSplit("abcdefghij", "z"); // "abcdefghij" testSplit("abcdefghij", "f"); // "abcde", "f", "ghi" testSplit("abcdefghij", "j"); // "abcdefghi", "j", "" testSplit("abcdefghij", "a"); // "", "a", "bcdefghij" testSplit("abcdefghij", "[bdfh]"); // "a", "b", "c", "d", "e", "f", "g", "h", "ij" } } 

Mi piace l’idea di StringTokenizer perché è Enumerable.
Ma è anche obsoleto e sostituisce con String.split che restituisce una noiosa stringa [] (e non include i delimitatori).

Così ho implementato un StringTokenizerEx che è un Iterable, e che prende una regexp vera per dividere una stringa.

Una regexp vera significa che non è una “sequenza di caratteri” ripetuta per formare il delimitatore:
‘o’ corrisponderà solo a ‘o’ e dividerà ‘ooo’ in tre delimitatori, con due stringhe vuote all’interno:

 [o], '', [o], '', [o] 

Ma regexp o + restituirà il risultato atteso quando si divide “aooob”

 [], 'a', [ooo], 'b', [] 

Per utilizzare questo StringTokenizerEx:

 final StringTokenizerEx aStringTokenizerEx = new StringTokenizerEx("boo:and:foo", "o+"); final String firstDelimiter = aStringTokenizerEx.getDelimiter(); for(String aString: aStringTokenizerEx ) { // uses the split String detected and memorized in 'aString' final nextDelimiter = aStringTokenizerEx.getDelimiter(); } 

Il codice di questa class è disponibile su DZone Snippets .

Come al solito per una risposta al codice-challenge (una class autonoma con casi di test inclusi), copia-incolla (in una directory ‘src / test’) ed eseguila . Il suo metodo main () illustra i diversi usi.


Nota: (modifica a fine 2009)

L’articolo Pensieri finali: Java Puzzler: Splitting Hairs fa un buon lavoro spiegando il bizzarro comportamento in String.split() .
Josh Bloch ha persino commentato in risposta a questo articolo:

Sì, questo è un dolore. FWIW, è stato fatto per un ottimo motivo: compatibilità con Perl.
Il ragazzo che l’ha fatto è Mike “madbot” McCloskey, che ora lavora con noi in Google. Mike ha fatto in modo che le espressioni regolari di Java passassero praticamente tutti i test delle espressioni regolari del 30K Perl (e funzionassero più velocemente).

Il Guava della biblioteca comune di Google contiene anche uno Splitter che è:

  • più semplice da usare
  • gestito da Google (e non da te)

Quindi potrebbe valere la pena di essere controllato. Dalla loro iniziale documentazione approssimativa (pdf) :

JDK ha questo:

 String[] pieces = "foo.bar".split("\\."); 

Va bene usarlo se vuoi esattamente quello che fa: – espressione regolare – risultato come una matrice – il suo modo di gestire i pezzi vuoti

Mini-puzzle: “, a ,, b,”. Split (“,”) restituisce …

 (a) "", "a", "", "b", "" (b) null, "a", null, "b", null (c) "a", null, "b" (d) "a", "b" (e) None of the above 

Risposta: (e) Nessuna delle precedenti.

 ",a,,b,".split(",") returns "", "a", "", "b" 

Solo i vuoti finali vengono saltati! (Chi conosce la soluzione alternativa per evitare il salto? È divertente …)

In ogni caso, il nostro Splitter è semplicemente più flessibile: il comportamento predefinito è semplicistico:

 Splitter.on(',').split(" foo, ,bar, quux,") --> [" foo", " ", "bar", " quux", ""] 

Se vuoi funzionalità extra, chiedi di loro!

 Splitter.on(',') .trimResults() .omitEmptyStrings() .split(" foo, ,bar, quux,") --> ["foo", "bar", "quux"] 

L’ordine dei metodi di configurazione non ha importanza: durante la divisione, il taglio avviene prima di controllare i vuoti.

Ecco una semplice implementazione pulita che è coerente con Pattern#split e funziona con pattern di lunghezza variabile, che dietro non supportano, ed è più facile da usare. È simile alla soluzione fornita da @letus.

 public static String[] split(CharSequence input, String pattern) { return split(input, Pattern.compile(pattern)); } public static String[] split(CharSequence input, Pattern pattern) { Matcher matcher = pattern.matcher(input); int start = 0; List result = new ArrayList<>(); while (matcher.find()) { result.add(input.subSequence(start, matcher.start()).toString()); result.add(matcher.group()); start = matcher.end(); } if (start != input.length()) result.add(input.subSequence(start, input.length()).toString()); return result.toArray(new String[0]); } 

Non eseguo controlli nulli qui, Pattern#split no, perché dovrei I. Non mi piace il if alla fine ma è richiesto per coerenza con il Pattern#split . In caso contrario, aggiungo incondizionatamente, risultando in una stringa vuota come ultimo elemento del risultato se la stringa di input termina con il pattern.

Mi converto in String [] per coerenza con Pattern#split , io uso la new String[0] piuttosto che la new String[result.size()] , vedi qui per il perché.

Ecco i miei test:

 @Test public void splitsVariableLengthPattern() { String[] result = Split.split("/foo/$bar/bas", "\\$\\w+"); Assert.assertArrayEquals(new String[] { "/foo/", "$bar", "/bas" }, result); } @Test public void splitsEndingWithPattern() { String[] result = Split.split("/foo/$bar", "\\$\\w+"); Assert.assertArrayEquals(new String[] { "/foo/", "$bar" }, result); } @Test public void splitsStartingWithPattern() { String[] result = Split.split("$foo/bar", "\\$\\w+"); Assert.assertArrayEquals(new String[] { "", "$foo", "/bar" }, result); } @Test public void splitsNoMatchesPattern() { String[] result = Split.split("/foo/bar", "\\$\\w+"); Assert.assertArrayEquals(new String[] { "/foo/bar" }, result); } 

Passa il 3 ° aurgum come “vero”. Restituirà anche i delimitatori.

 StringTokenizer(String str, String delimiters, true); 

Pubblicherò anche le mie versioni di lavoro (la prima è molto simile a Markus).

 public static String[] splitIncludeDelimeter(String regex, String text){ List list = new LinkedList<>(); Matcher matcher = Pattern.compile(regex).matcher(text); int now, old = 0; while(matcher.find()){ now = matcher.end(); list.add(text.substring(old, now)); old = now; } if(list.size() == 0) return new String[]{text}; //adding rest of a text as last element String finalElement = text.substring(old); list.add(finalElement); return list.toArray(new String[list.size()]); } 

Ed ecco la seconda soluzione e il suo giro del 50% più veloce del primo:

 public static String[] splitIncludeDelimeter2(String regex, String text){ List list = new LinkedList<>(); Matcher matcher = Pattern.compile(regex).matcher(text); StringBuffer stringBuffer = new StringBuffer(); while(matcher.find()){ matcher.appendReplacement(stringBuffer, matcher.group()); list.add(stringBuffer.toString()); stringBuffer.setLength(0); //clear buffer } matcher.appendTail(stringBuffer); ///dodajemy reszte ciagu list.add(stringBuffer.toString()); return list.toArray(new String[list.size()]); } 

Non conosco una funzione esistente nell’API Java che esegue questa operazione (che non vuol dire che non esista), ma ecco la mia implementazione (uno o più delimitatori verranno restituiti come un singolo token, se lo si desidera ogni delimitatore deve essere restituito come token separato, sarà necessario un po ‘di adattamento):

 static String[] splitWithDelimiters(String s) { if (s == null || s.length() == 0) { return new String[0]; } LinkedList result = new LinkedList(); StringBuilder sb = null; boolean wasLetterOrDigit = !Character.isLetterOrDigit(s.charAt(0)); for (char c : s.toCharArray()) { if (Character.isLetterOrDigit(c) ^ wasLetterOrDigit) { if (sb != null) { result.add(sb.toString()); } sb = new StringBuilder(); wasLetterOrDigit = !wasLetterOrDigit; } sb.append(c); } result.add(sb.toString()); return result.toArray(new String[0]); } 

Suggerisco di usare Pattern and Matcher, che quasi certamente otterrà ciò che desideri. La tua espressione regolare dovrà essere un po ‘più complicata di quella che stai usando in String.split.

Non penso sia ansible con String#split , ma puoi usare StringTokenizer , anche se questo non ti permette di definire il tuo delimitatore come un’espressione regolare, ma solo come una class di caratteri a una sola cifra:

 new StringTokenizer("Hello, world. Hi!", ",.!", true); // true for returnDelims 

Se ti puoi permettere, usa il metodo di sostituzione di Java (CharSequence target, CharSequence replacement) e riempi un altro delimitatore per dividere con. Esempio: voglio dividere la stringa “boo: and: foo” e mantenere “:” alla sua stringa di destra.

 String str = "boo:and:foo"; str = str.replace(":","newdelimiter:"); String[] tokens = str.split("newdelimiter"); 

Nota importante: funziona solo se non hai più “newdelimiter” nella tua stringa! Quindi, non è una soluzione generale. Ma se conosci un CharSequence di cui puoi essere sicuro che non apparirà mai nella String, questa è una soluzione molto semplice.

Un’altra soluzione candidata che utilizza una regex. Mantiene ordine token, corrisponde correttamente a più token dello stesso tipo in una riga. Il rovescio della medaglia è che la regex è abbastanza ctriggers.

 package javaapplication2; import java.util.ArrayList; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; public class JavaApplication2 { /** * @param args the command line arguments */ public static void main(String[] args) { String num = "58.5+variable-+98*78/96+a/78.7-3443*12-3"; // Terrifying regex: // (a)|(b)|(c) match a or b or c // where // (a) is one or more digits optionally followed by a decimal point // followed by one or more digits: (\d+(\.\d+)?) // (b) is one of the set + * / - occurring once: ([+*/-]) // (c) is a sequence of one or more lowercase latin letter: ([az]+) Pattern tokenPattern = Pattern.compile("(\\d+(\\.\\d+)?)|([+*/-])|([az]+)"); Matcher tokenMatcher = tokenPattern.matcher(num); List tokens = new ArrayList<>(); while (!tokenMatcher.hitEnd()) { if (tokenMatcher.find()) { tokens.add(tokenMatcher.group()); } else { // report error break; } } System.out.println(tokens); } } 

Uscita di esempio:

 [58.5, +, variable, -, +, 98, *, 78, /, 96, +, a, /, 78.7, -, 3443, *, 12, -, 3] 

Risposta rapida: usa limiti non fisici come \ b per dividere. Proverò a sperimentare per vedere se funziona (usato in PHP e JS).

È ansible, e il tipo di lavoro, ma potrebbe dividere troppo. In realtà, dipende dalla stringa che vuoi dividere e dal risultato che ti serve. Fornisci maggiori dettagli, ti aiuteremo meglio.

Un altro modo è quello di fare la tua divisione, catturando il delimitatore (supponendo che sia variabile) e aggiungendolo successivamente al risultato.

Il mio test rapido:

 String str = "'ab','cd','eg'"; String[] stra = str.split("\\b"); for (String s : stra) System.out.print(s + "|"); System.out.println(); 

Risultato:

 '|ab|','|cd|','|eg|'| 

Un po ‘troppo … 🙂

Tweaked Pattern.split () per includere pattern abbinati all’elenco

aggiunto

 // add match to the list matchList.add(input.subSequence(start, end).toString()); 

Fonte completa

 public static String[] inclusiveSplit(String input, String re, int limit) { int index = 0; boolean matchLimited = limit > 0; ArrayList matchList = new ArrayList(); Pattern pattern = Pattern.compile(re); Matcher m = pattern.matcher(input); // Add segments before each match found while (m.find()) { int end = m.end(); if (!matchLimited || matchList.size() < limit - 1) { int start = m.start(); String match = input.subSequence(index, start).toString(); matchList.add(match); // add match to the list matchList.add(input.subSequence(start, end).toString()); index = end; } else if (matchList.size() == limit - 1) { // last one String match = input.subSequence(index, input.length()) .toString(); matchList.add(match); index = end; } } // If no match was found, return this if (index == 0) return new String[] { input.toString() }; // Add remaining segment if (!matchLimited || matchList.size() < limit) matchList.add(input.subSequence(index, input.length()).toString()); // Construct result int resultSize = matchList.size(); if (limit == 0) while (resultSize > 0 && matchList.get(resultSize - 1).equals("")) resultSize--; String[] result = new String[resultSize]; return matchList.subList(0, resultSize).toArray(result); } 

Ecco una versione groovy basata su parte del codice sopra, nel caso in cui aiuta. È breve, comunque. Condizionalmente include la testa e la coda (se non sono vuoti). L’ultima parte è un demo / test case.

 List splitWithTokens(str, pat) { def tokens=[] def lastMatch=0 def m = str=~pat while (m.find()) { if (m.start() > 0) tokens < < str[lastMatch..this is the title',/< [^>]+>/], ['beforethis is the titleafter',/< [^>]+>/] ].each { println splitWithTokens(*it) } 

Una soluzione estremamente ingenua e inefficiente, che funziona comunque. Utilizzare split due volte sulla stringa e quindi concatenare i due array

 String temp[]=str.split("\\W"); String temp2[]=str.split("\\w||\\s"); int i=0; for(String string:temp) System.out.println(string); String temp3[]=new String[temp.length-1]; for(String string:temp2) { System.out.println(string); if((string.equals("")!=true)&&(string.equals("\\s")!=true)) { temp3[i]=string; i++; } // System.out.println(temp.length); // System.out.println(temp2.length); } System.out.println(temp3.length); String[] temp4=new String[temp.length+temp3.length]; int j=0; for(i=0;i 
  String expression = "((A+B)*CD)*E"; expression = expression.replaceAll("\\+", "~+~"); expression = expression.replaceAll("\\*", "~*~"); expression = expression.replaceAll("-", "~-~"); expression = expression.replaceAll("/+", "~/~"); expression = expression.replaceAll("\\(", "~(~"); //also you can use [(] instead of \\( expression = expression.replaceAll("\\)", "~)~"); //also you can use [)] instead of \\) expression = expression.replaceAll("~~", "~"); if(expression.startsWith("~")) { expression = expression.substring(1); } String[] expressionArray = expression.split("~"); System.out.println(Arrays.toString(expressionArray)); 

Se sei preoccupato per le complicazioni che le cose look-ahead / look-behind potrebbero introdurre, e vuoi solo un solido metodo di utilità che possa far fronte a qualsiasi modello di gettone e ai separatori che ti vengono lanciati. (Che probabilmente è il caso!)

NB sorpreso di scoprire che la gente di Apache Commons non sembra averlo fornito, ad esempio in StringUtils .

Inoltre suggerisco che questo dovrebbe essere un flag in Pattern : i..e INCLUDE_SEPARATORS .

Ma questo è abbastanza semplice se usi le classi Pattern e Matcher destra:

  // NB could be a different spec for identifying tokens, of course! Pattern sepAndTokenPattern = Pattern.compile("(.*?)(\\w+)"); Matcher matcher = sepAndTokenPattern.matcher( stringForTokenising ); List tokenAndSeparatorList = new ArrayList(); // for most processing purposes you are going to want to know whether your // combined list of tokens and separators begins with a token or separator boolean startsWithToken = true; int matchEnd = -1; while (matcher.find()) { String preSep = matcher.group(1); if (!preSep.isEmpty()) { if( tokenAndSeparatorList.isEmpty() ){ startsWithToken = false; } // in implementation you wouldn't want these | characters, of course tokenAndSeparatorList.add("|" + preSep + "|"); // add sep } tokenAndSeparatorList.add("|" + matcher.group(2) + "|"); // add token matchEnd = matcher.end(); } // get trailing separator, if there is one: if( matchEnd != -1 ){ String trailingSep = stringForTokenising.substring( matchEnd ); if( ! trailingSep.isEmpty() ){ tokenAndSeparatorList.add( "|" + trailingSep + "|" ); } } System.out.println(String.format("# starts with token? %b - matchList %s", startsWithToken, tokenAndSeparatorList)); 

I don’t know Java too well, but if you can’t find a Split method that does that, I suggest you just make your own.

 string[] mySplit(string s,string delimiter) { string[] result = s.Split(delimiter); for(int i=0;i 

Its not too elegant, but it'll do.