Wie füge ich für alle Zeilen außer der letzten ein Zeilenumbruchzeichen hinzu?
Frage
Ich iteriere durch eine HashMap (siehe meine frühere Frage für weitere Einzelheiten) und Erstellen einer Zeichenfolge, die aus den in der Karte enthaltenen Daten besteht.Für jeden Artikel werde ich eine neue Zeile haben, aber für den allerletzten Artikel möchte ich keine neue Zeile.Wie kann ich das erreichen?Ich dachte, ich könnte irgendwie überprüfen, ob der Eintrag der letzte ist oder nicht, aber ich bin mir nicht sicher, wie ich das eigentlich machen soll.
Danke!
Lösung
ändern Sie Ihren Denkprozess von „anhängen eine Linie bricht alle, aber das letzte Mal“ auf „voranstellen, eine Linie brechen alle, aber das erste Mal“:
boolean first = true;
StringBuilder builder = new StringBuilder();
for (Map.Entry<MyClass.Key,String> entry : data.entrySet()) {
if (first) {
first = false;
} else {
builder.append("\n"); // Or whatever break you want
}
builder.append(entry.key())
.append(": ")
.append(entry.value());
}
Andere Tipps
ein Verfahren (mit Entschuldigungen zu Jon Skeet für einen Teil seines Java-Code zu leihen):
StringBuilder result = new StringBuilder();
string newline = "";
for (Map.Entry<MyClass.Key,String> entry : data.entrySet())
{
result.append(newline)
.append(entry.key())
.append(": ")
.append(entry.value());
newline = "\n";
}
Was ist das?
StringBuilder result = new StringBuilder();
for(Map.Entry<MyClass.Key,String> entry : data.entrySet())
{
builder.append(entry.key())
.append(": ")
.append(entry.value())
.append("\n");
}
return builder.substring(0, builder.length()-1);
Obligatorische Entschuldigungen und dank sowohl Jon und Joel für „Borgen“ von ihrem Beispiel.
Ususally für diese Art von Dingen, die ich verwende Apache-Commons-lang StringUtils # join . Zwar ist es nicht wirklich schwer ist, alle diese Arten von Utility-Funktionen zu schreiben, ist es immer besser zu bestehenden bewährten Bibliotheken wiederverwenden. Apache-Commons so voll von nützlichen Sachen ist!
Wenn Sie Iterator verwenden, anstatt für ... jeder Code könnte wie folgt aussehen:
StringBuilder builder = new StringBuilder();
Iterator<Map.Entry<MyClass.Key, String>> it = data.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<MyClass.Key, String> entry = it.next();
builder.append(entry.key())
.append(": ")
.append(entry.value());
if (it.hasNext()) {
builder.append("\n");
}
}
Dies ist wahrscheinlich ein besseres Beispiel ...
final StringBuilder buf = new StringBuilder();
final String separator = System.getProperty("line.separator"); // Platform new line
for (Map.Entry<MyClass.Key,String> entry: data.entrySet()) {
builder.append(entry.key())
.append(": ")
.append(entry.value())
.append(separator);
}
// Remove the last separator and return a string to use.
// N.b. this is likely as efficient as just using builder.toString()
// which would also copy the buffer, except we have 1 char less
// (i.e. '\n').
final String toUse = builder.substring(0, builder.length()-separator.length()-1);
Hier ist meine prägnante Version, die die Länge Eigenschaft anstelle einer zusätzlichen Variable String verwendet:
StringBuilder builder = new StringBuilder();
for (Map.Entry<MyClass.Key,String> entry : data.entrySet())
{
builder.append(builder.length() > 0 ? "\n" : "")
.append(entry.key())
.append(": ")
.append(entry.value());
}
(Apologies und dank sowohl Jon und Joel für "Leihen" von ihren Beispielen.)
Eine Lösung ist eine benutzerdefinierte Wrapper Stringbuilder zu erstellen. Es kann nicht verlängert werden, so dass ein Wrapper erforderlich ist.
public class CustomStringBuilder {
final String separator = System.getProperty("line.separator");
private StringBuilder builder = new StringBuilder();
public CustomStringBuilder appendLine(String str){
builder.append(str + separator);
return this;
}
public CustomStringBuilder append(String str){
builder.append(str);
return this;
}
public String toString() {
return this.builder.toString();
}
}
Die Umsetzung wie so:
CustomStringBuilder builder = new CustomStringBuilder();
//iterate over as needed, but a wrapper to StringBuilder with new line features.
builder.appendLine("data goes here");
return builder.toString();
Dies hat einige Nachteile haben:
- Das Schreiben von Code, dass ist in der Regel nicht "Domain / business" centric
- Nicht mit Open-Source-Standardlösung wie: StringUtils.join
- gezwungen, eine Klasse zu erhalten, die eine JDK Klasse umschließt, die letzte und damit ist Updates langfristig erforderlich.
ging ich mit der StringUtils.join Lösung über Sammlungen für Iterieren und sogar leichte Build-Methode Muster Aufbau im Code.
Ihre foreach-Schleife geht, um durch die Datei Unter der Annahme, nur eine neue Zeile zu jeder Zeichenfolge hinzuzufügen und die letzte neue Zeile, wenn die Schleife beendet zu entfernen.
Nicht sicher, ob dies die beste, aber es ist die einfachere Art und Weise zu tun:
Schleife durch alle Werte und hängen die \ n normalerweise im Stringbuffer. Dann tun so etwas wie dieses
sb.setLength(sb.length()-1);
Dies ist, wo ein Verfahren beizutreten, ergänzen Split, würde sich als nützlich, denn dann könnte man einfach alle Elemente verbinden, um eine neue Zeile als Trennzeichen verwenden, und natürlich ist es nicht eine neue Zeile an das Ende anhängen des Ergebnisses; das ist, wie ich es in verschiedenen Skriptsprachen (Javascript, PHP, usw.).
Wenn Sie Klasse Separator , Sie tun können,
StringBuilder buf = new StringBuilder();
Separator separator = new Separator("\n");
for (Map.Entry<MyClass.Key,String> entry: data.entrySet()) {
builder.append(separator)
.append(entry.key())
.append(": ")
.append(entry.value());
}
Die Trenn druckt in leeren String auf dem ersten Gebrauch, und der Separator auf alle nachfolgenden Verwendungen.
Ha! Dank href="https://stackoverflow.com/questions/654054/separated-string-created-in-loop/654102#654102"> diesen Beitrag ich einen anderen Weg gefunden habe, dies zu tun:
public static class Extensions
{
public static string JoinWith(this IEnumerable<string> strings, string separator)
{
return String.Join(separator, strings.ToArray());
}
}
Natürlich ist dies in C # und Java jetzt wird (noch) nicht die Erweiterungsmethode unterstützen, aber Sie sollten in der Lage sein, um es anzupassen je nach Bedarf - die Hauptsache ist die Verwendung von String.Join
ist sowieso, und ich bin sicher, Java hat einige analog dazu.
Beachten Sie auch, dass dies bedeutet eine zusätzliche Iteration der Saiten zu tun, weil Sie zuerst das Array erstellen muss und dann über die iteriert Zeichenfolge zu bauen. Auch Sie wird das Array erstellen, in denen mit anderen Methoden könnten Sie in der Lage zu bekommen, indem sie mit einem IEnumerable, dass nur eine Zeichenfolge im Speicher hält auf einmal. Aber Ich mag die zusätzliche Klarheit.
Natürlich, da die Erweiterungsmethode Fähigkeit Sie konnte nur abstrakt jeder des anderen Code in ein Erweiterungsmethode auch.
Lassen Bibliotheken dies für Sie tun.
import com.sun.deploy.util.StringUtils;
sowie viele andere haben StringUtils, die eine Join-Methode hat. Sie können dies in einer Zeile ein:
StringUtils.join(list, DELIMITER);
Aber für mehr Kontext, hier ist, wie Sie es mit einem hashmap tun könnten.
public static String getDelimitatedData(HashMap<String, String> data) {
final String DELIMITER = "\n"; //Should make this a variable
ArrayList<String> entries = new ArrayList<>();
for (Map.Entry<String, String> entry : data.entrySet()) {
entries.add(entry.getKey() + ": " + entry.getValue());
}
return StringUtils.join(entries, DELIMITER);
}
Verwenden Sie die JDK-APIs zum Verknüpfen von Zeichenfolgen:
String result = data.stream()
.map((k,v) -> String.format("%s : %s", k, v)
.collect(Collectors.joining("\n"));