最後の行を除くすべての行に改行文字を追加するにはどうすればよいですか?
質問
HashMapを反復処理しています(詳細については以前の質問)と、Mapに含まれるデータで構成される文字列を作成します。各アイテムには新しい行がありますが、最後のアイテムには新しい行は必要ありません。どうすればこれを達成できますか?エントリが最後のものかどうかを確認するために何らかのチェックができると考えていましたが、実際にそれを行う方法はわかりません。
ありがとう!
解決
思考プロセスを<!> quotから変更します;最後を除いてすべて改行を追加します<!> quot; <!> quot;最初以外はすべて改行を追加する<!> quot;:
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());
}
他のヒント
1つの方法(Jon SkeetがJavaコードの一部を借用したことを謝罪):
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";
}
これはどうですか?
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);
義務的な謝罪と<!> quot; borrowing <!> quot;に対するJonとJoelの両方への感謝。例から。
通常、この種のことにはapache-commons-lang StringUtils#join 。これらすべての種類のユーティリティ機能を書くことはそれほど難しくありませんが、既存の実績のあるライブラリを再利用することは常により良いです。 Apache-commons には、そのような便利なものがたくさんあります!
for ... eachの代わりにイテレータを使用する場合、コードは次のようになります。
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");
}
}
これはおそらくより良い例です...
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);
追加の変数の代わりにStringBuilderのlengthプロパティを使用する簡潔なバージョンを次に示します。
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());
}
(<!> quot; borrowing <!> quot;の例からJonとJoelの両方に謝罪します。)
1つの解決策は、StringBuilderのカスタムラッパーを作成することです。拡張できないため、ラッパーが必要です。
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();
}
}
そのような実装:
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();
これにはいくつかの欠点があります:
- 通常は<!> quot; domain / business <!> quotではない記述コード中心
- StringUtils.joinのようなオープンソースの標準ソリューションを使用しない
- 最終的なJDKクラスをラップするクラスを維持しなければならないため、更新には長期が必要です。
コレクションを繰り返し処理し、コード内で軽量のビルドメソッドパターンを構築するために、StringUtils.joinソリューションを使用しました。
foreachループがすべての文字列に新しい行を追加し、ループの終了時に最後の新しい行を削除するためにファイルを通過すると仮定します。
これが最善かどうかはわかりませんが、<!>#180;の方が簡単です:
すべての値をループし、通常は文字列バッファーに\ nを追加します。次に、このようなことをします
sb.setLength(sb.length()-1);
これは、分割を補完する結合方法が便利な場所です。これは、セパレータとして改行を使用してすべての要素を結合することができ、もちろん改行を最後に追加しないためです結果のさまざまなスクリプト言語(Javascript、PHPなど)でそれを行う方法です。
クラスセパレーターを使用すると、できること
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());
}
区切り文字は、最初の使用時に空の文字列で印刷され、その後のすべての使用時に区切り文字が印刷されます。
はい! この投稿のおかげで、これを行う別の方法が見つかりました。
public static class Extensions
{
public static string JoinWith(this IEnumerable<string> strings, string separator)
{
return String.Join(separator, strings.ToArray());
}
}
もちろんこれは現在C#であり、Javaは(まだ)拡張メソッドをサポートしませんが、必要に応じて拡張メソッドを調整できるはずです<!>#8212;主なことは、とにかくString.Join
を使用することであり、javaにはそのための類似物があると確信しています。
これは、最初に配列を作成し、次にそれを繰り返して文字列を作成する必要があるため、文字列の追加の反復を行うことを意味することにも注意してください。また、配列を 作成します。他のメソッドでは、一度に1つの文字列のみをメモリに保持するIEnumerableで取得できる場合があります。しかし、私は余分な明快さが本当に好きです。
もちろん、拡張メソッド機能があれば、他のコードを拡張メソッドに抽象化することもできます。
ライブラリがこれを行うようにします。
import com.sun.deploy.util.StringUtils;
他の多くのユーザーと同様に、StringUtilsには結合メソッドがあります。これは1行で行えます:
StringUtils.join(list, DELIMITER);
しかし、より多くのコンテキストのために、ハッシュマップを使用してこれを行うことができます。
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);
}
APIを結合するJDK文字列を使用します。
String result = data.stream()
.map((k,v) -> String.format("%s : %s", k, v)
.collect(Collectors.joining("\n"));