2010-08-03 19 views
290

Wenn Sie eine Auflistung durchlaufen müssen und eine Zeichenfolge für die einzelnen Daten durch ein Trennzeichen trennen müssen, wird am Ende immer ein zusätzliches Trennzeichen angezeigt, z.Letztes Zeichen eines StringBuilders entfernen?

for(String serverId : serverIds) { 
sb.append(serverId); 
sb.append(","); 
} 

gibt so etwas wie: serverId_1, serverId_2, serverId_3,

Ich mag würde das letzte Zeichen in dem String löschen (ohne Konvertierung, weil ich es immer noch nach dieser Schleife benötigen).

+4

Warum nicht Strings verbinden? –

+8

Wenn Sie mit Strings "String-Verkettung" meinen, hängt das von der Anzahl der Strings und deren Länge ab. Die Verwendung eines String-Builders ist effizienter, wenn Sie unabhängig von ihrer Größe viele Strings einfügen, da Strings unveränderbar sind. Jedes Mal, wenn Sie Zeichenketten verketten, erstellen Sie eine neue resultierende Zeichenkette (die eigentlich ein Zeichenketten-Array ist). String-Builder sind im Wesentlichen eine Liste von Zeichen, die erst dann zu einer unveränderlichen Zeichenfolge werden, wenn Sie die toString() -Methode aufrufen. – dyslexicanaboko

+2

Wenn Sie Java 8 verwenden, verwenden Sie einfach 'StringJoiner': http://StackOverflow.com/a/29169233/901641 – ArtOfWarfare

Antwort

478

Andere haben die deleteCharAt Verfahren darauf hingewiesen, aber hier ist ein weiterer alternativer Ansatz:

String prefix = ""; 
for (String serverId : serverIds) { 
    sb.append(prefix); 
    prefix = ","; 
    sb.append(serverId); 
} 

Alternativ können Sie die Joiner Klasse von Guava :)

Ab Java 8 ist StringJoiner Teil des Standard JRE.

+0

Kann nicht '' '' 'und' '' '' char'' sein? Wenn StringBuilder hauptsächlich für die Performance verwendet wird, warum nicht den ganzen Weg gehen? –

+6

@Coronatus: Nein, denn "" ist die * Abwesenheit * von irgendwelchen Zeichen, nicht ein einzelnes Zeichen. –

+25

führt kein Präfix = ","; Jeder Schleifenzyklus beeinflusst die Leistung? – Harish

112
sb.deleteCharAt(sb.length()-1) 
+3

Hm ... Ich verpasste die Löschfunktionen in der Javadoc! aha) Ich bin es gewohnt, nach "remove" zu suchen Danke! – Matthew

+23

Dies wird zu viel hochgeregelt, aber es ist nicht effizient, es tut eine system.arraycopy. Was sagte @Rohit Reddy Korrapolu. –

+7

Es ist unsicher für 'sb.length() == 0' auch – Matthias

287

Eine weitere einfache Lösung ist:

sb.setLength(sb.length() - 1); 

Eine kompliziertere Lösung:

Die obige Lösung geht davon aus, dass sb.length() > 0 ... dh es wird ein "letztes Zeichen" zu entfernen . Wenn Sie diese Annahme nicht machen können und/oder Sie nicht mit der Ausnahme umgehen können, die sich ergeben würde, wenn die Annahme falsch ist, überprüfen Sie zuerst die Länge des StringBuilders; z.B.

// Readable version 
if (sb.length() > 0) { 
    sb.setLength(sb.length() - 1); 
} 

oder

// Concise but harder-to-read version of the above. 
sb.setLength(Math.max(sb.length() - 1, 0)); 
+14

Sehr nette Lösung.Geringste Auswirkung auf die Leistung und den geringsten Code erforderlich :) –

+0

@fglez - Diese Lösung wurde für Anwendungsfälle entwickelt, bei denen eine Überprüfung nicht erforderlich ist oder ein SIOBEE ein akzeptables Ergebnis ist. Das Hinzufügen des Schecks bedeutet, dass dies keine "einfache Lösung" mehr ist. –

5
StringBuilder sb = new StringBuilder(); 
sb.append("abcdef"); 
sb.deleteCharAt(sb.length() - 1); 
assertEquals("abcde",sb.toString()); 
// true 
6

Alternativ

StringBuilder result = new StringBuilder(); 
    for(String string : collection) { 
     result.append(string); 
     result.append(","); 
    } 
    return result.substring(0, result.length() - 1) ; 
+0

Verwendbar, da Sie ein "." Am Ende. – artfullyContrived

3

Noch eine weitere Alternative:

public String join(Collection<String> collection, String seperator) { 
    if (collection.isEmpty()) return ""; 

    Iterator<String> iter = collection.iterator(); 
    StringBuilder sb = new StringBuilder(iter.next()); 
    while (iter.hasNext()) { 
     sb.append(seperator); 
     sb.append(iter.next()); 
    } 

    return sb.toString(); 
} 
+0

Plus one .. Ähnlich wie Apache Joiner-Implementierung ... – Ahamed

10

Eine weitere Alternative

for(String serverId : serverIds) { 
    sb.append(","); 
    sb.append(serverId); 
} 
sb.deleteCharAt(0); 
+2

Sollte besser sein als das letzte Zeichen zu entfernen, da dies Größenberechnungen erfordert. Wenn das Entfernen des ersten Zeichens nicht dazu führt, dass Daten verschoben werden ... – slott

33

In diesem Fall

sb.setLength(sb.length() - 1); 

ist vorzuziehen, da sie nur den letzten Wert '\0' zuweisen, während letzte Zeichen zu löschen tut System.arraycopy

+1

Der Aufruf 'setLength' weist dem letzten Wert nichts zu. Java-Zeichenfolgenpuffer sind nicht null/null terminiert. In der Tat aktualisiert 'setLength' einfach ein' length'-Feld. –

+0

@Rohit Reddy Korrapolu: Aber die 'arraycopy' kopiert 0 Elemente, also denke ich, dass es weg optimiert werden kann. – maaartinus

+2

_Wenn das Argument newLength größer oder gleich der aktuellen Länge ist, werden genügend Nullzeichen ('\ u0000') angehängt, so dass die Länge zum newLength-Argument wird._ Was nicht der Fall ist. – fglez

42

Ab Java 8, gibt es eine neue StringJoiner Klasse gebaut in

StringJoiner sj = new StringJoiner(", "); 
for (String serverId : serverIds) { 
    sj.add(serverId) 
} 
0

ich so etwas wie dies tue.:

StringBuilder stringBuilder = new StringBuilder(); 
    for (int i = 0; i < value.length; i++) { 
     stringBuilder.append(values[i]); 
     if (value.length-1) { 
      stringBuilder.append(", "); 
     } 
    } 
21

Ermitteln Sie einfach die Position des letzten Zeichenvorkommens.

for(String serverId : serverIds) { 
sb.append(serverId); 
sb.append(","); 
} 
sb.deleteCharAt(sb.lastIndexOf(",")); 

Da lastIndexOf eine Rückwärtssuche durchführen, und Sie wissen, dass es beim ersten Versuch finden, die Leistung wird hier nicht ein Problem sein.

+0

Sie werden sicher sein, dass das letzte Zeichen ein ',' ist, weil es die letzte Anweisung der 'for-Schleife 'war. Das 'lastInfexOf' ist mehr für Lesbarkeit und um es ein Kinderspiel zu machen, wenn Sie nicht daran denken wollen, ob es 0-indexiert ist oder nicht. Außerdem müssen Sie sich nicht mit der Länge des Stringbuilders einmischen. Es ist nur für die Bequemlichkeit. –

2

Um reinit (die Leistung beeinträchtigen) vonzu vermeidenVerwendung TextUtils.isEmpty:

  String prefix = ""; 
      for (String item : list) { 
       sb.append(prefix); 
       if (TextUtils.isEmpty(prefix)) 
        prefix = ","; 
       sb.append(item); 
      } 
+0

Zu welcher Art von Paket gehören TestUtils? – Markus

+0

@Markus android.text.TextUtils – NickUnuchek

0

Sie können versuchen, Klasse ‚Joiner‘ zu verwenden, anstatt das letzte Zeichen aus dem erzeugten Text zu entfernen;

   List<String> textList = new ArrayList<>(); 
       textList.add("text1"); 
       textList.add("text2"); 
       textList.add("text3"); 

       Joiner joiner = Joiner.on(",").useForNull("null"); 
       String output = joiner.join(textList); 

       //output : "text1,text2,text3" 
0

ist hier eine andere Lösung:

for(String serverId : serverIds) { 
    sb.append(","); 
    sb.append(serverId); 
} 

String resultingString = ""; 
if (sb.length() > 1) { 
    resultingString = sb.substring(1); 
} 
+1

Oh ... Ich verstehe. Sie rufen die Teilzeichenfolge im StringBuilder nicht als String ab. –

+0

Aber das ist nur eine kleine Variante von Zakis Lösung von 2010. –

0

ich persönlich einen Backspace Charakter anhängen möchte (oder mehr länger "Trennzeichen") am Ende:

for(String serverId : serverIds) { 
    sb.append(serverId); 
    sb.append(","); 
} 

sb.append('\b'); 

Beachten Sie, dass es hat Probleme:

  • wie \b angezeigt wird, hängt von der Umgebung,
  • die length() des String Inhalts könnte

Wenn \b sieht nicht gut aus, und die Länge spielt keine Rolle, von der Länge der „visibile“ Zeichen unterschiedlich sein wie die Protokollierung eines Konsole, das scheint mir gut genug zu sein.

Verwandte Themen