StringSplit optimieren

nrg

Top Contributor
Hallo Zusammen,

habe folgende Splitmethode:
Java:
	public static String[] split(String str, String delim) {
		StringBuilder sb = new StringBuilder();
		List<String> tokens = new ArrayList<String>();
		int length = str.length(), delimLength = delim.length();
		for (int i = 0; i < length; i++) {
			if (i + delimLength > length || !str.substring(i, i + delimLength).equals(delim)) {
				sb.append(str.charAt(i));
			} else {
				tokens.add(sb.toString());
				sb.setLength(0);
				i += delimLength - 1;
			}
		}
		tokens.add(sb.toString());
		String[] ret = new String[tokens.size()];
		return tokens.toArray(ret);
	}

diese ist leider - wer hätte es gedacht :/ - nur halb so schnell wie String#split. (edit: bzw nicht halb so schnell, sondern ballert doppeltsoviel Speicher zu.... Den Benchmarkvergleich will ich glaub garnicht wissen ;))

An String#split passt mir aber folgendes nicht:
Java:
System.out.println("Hallo;Welt;das;ist;ein;;;;;;".split(";").length);

Ausgabe: 5

Ich will aber, dass er hier 11 tokens liefert. Also bleibt mir imho nicht viel mehr übrig, als das selbst zu schreiben. Nur ist mir meine Lösung noch zu lahm. Habt ihr vllt Verbesserungsvorschläge?

Danke und Grüße
Andi
 
Zuletzt bearbeitet:
S

SlaterB

Gast
Java:
System.out.println("Hallo;Welt;das;ist;ein;;;;;;".split(";",999).length);
liefert 11,
die genaue Bedeutung vergesse ich immer wieder falls sie überhaupt klar belegt ist, bitte erstmal selber in der API nachlesen falls interessiert,
ob das nicht auch schon langsamer ist kannst du auch testen

bei deinem Programm wäre der delim-Test mit substring zu verbessern, dort gehört eine Schleife rein, nur mit charAt() delim und string an der richtigen Position durchgehen und vergleichen,
für den recht häufigen Fall mit delim.length() == 1 lohnt sich vielleicht gar eine optimierte Variante einfach nur mit einem charAt()-Vergleich ohne Schleife
 

Paeddah

Mitglied
In freier Anlehnung an die Originalfunktionalität:

Java:
  public static String[] extendedSplit(String input, String delim) {
    Pattern compile = Pattern.compile(delim);
    Matcher matcher = compile.matcher(input);
    int index = 0;
    ArrayList<String> matchList = new ArrayList<String>();
    while (matcher.find()) {
      String sub = input.subSequence(index, matcher.start()).toString();
      index = matcher.end();
      matchList.add(sub);
    }
    matchList.add(input.subSequence(index, input.length()).toString());
    return matchList.toArray(new String[matchList.size()]);
  }

Der 2. Parameter von split() kennzeichnet die maximale Anzahl an Treffern.
 

nrg

Top Contributor
wusste bis jetzt noch gar nicht, dass split überladen ist. mit String#split(str, -1) sollte er mir immer alle Tokens liefern.
Beim Split unter Berücksichtigung von Qualifier/Quotes werde ich's dann wohl selber schreiben und deinen Verbesserungsvorschlag mit aufnehmen. Vielen Dank
 

Andi_CH

Top Contributor
Einfachste Lösung: + ";a" und dann das letzte Element im Array ignorieren

Jezte sehe ich endlich wie du das gemeint hast - ich dachte zuerst du willst jedes ; durch ;a ersetzten. Hinten einmal anhängen geht natürlich.

Es steht sogar in der API-Doku
This method works as if by invoking the two-argument split method with the given expression and a limit argument of zero. Trailing empty strings are therefore not included in the resulting array.


Aber für den ganz allgemeinen Fall ist
Code:
split(";",999)
auch etwas gefährlich ;-) wie oft haben wir schon gehört: "Das reicht gaaaaaaanz sicher" :)
The limit parameter controls the number of times the pattern is applied and therefore affects the length of the resulting array.

Man kann ja immer noch die ";" zählen und diesen Wert verwenden.
 

nrg

Top Contributor
Aber für den ganz allgemeinen Fall ist
Code:
split(";",999)
auch etwas gefährlich ;-) wie oft haben wir schon gehört: "Das reicht gaaaaaaanz sicher" :)


Man kann ja immer noch die ";" zählen und diesen Wert verwenden.

hab doch schon grad geschrieben, dass ich mit split(";", -1) sehr gut leben kann. Das wird dann auch nicht gefährlich, weil es immer reicht ;)

@Paeddah: Deine Splitmethode finde ich ganz interessant. Läuft zwar auch nicht ganz so gut, wie der Split von Sun aber immerhin besser als meiner :). Wenn man dort jetzt noch die Berücksichtung von Quailifier/Quotes einbauen könnte, wäre das natürlich perfekt. Hast du da vielleicht eine Idee?

ich korrigiere: läuft genauso gut, wie String#split(";", -1) (zumindest von der Speicherauslastung - Benchmarks wurden, wie gesagt, von mir nicht durchgeführt). Den Qualifiersplit habe ich jetzt etwas umgeschrieben
@Lumaraf: werd ich auch mal noch testen

Danke für die Hilfe
 
Zuletzt bearbeitet:

Lumaraf

Bekanntes Mitglied
Insofern man keine Regulären Ausdrücke als Trenner benötigt hätte ich noch eine performantere Alternative.

Java:
	private static String[] fastSplit(final String source, final String search)
	{
		int indexOf = source.indexOf(search);
		if (indexOf == -1)
			return new String[] { source };
		else {
			ArrayList<String> tokenList = new ArrayList<String>();
			int lastIndex = 0;
			do {
				tokenList.add(source.substring(lastIndex, indexOf));
				lastIndex = indexOf + search.length();

				indexOf = source.indexOf(search, lastIndex);
			} while (indexOf >= lastIndex);
			tokenList.add(source.substring(lastIndex));
			return tokenList.toArray(new String[tokenList.size()]);
		}
	}
 

Ähnliche Java Themen


Oben