Как мне добавить символ новой строки для всех строк, кроме последней?

StackOverflow https://stackoverflow.com/questions/448320

  •  19-08-2019
  •  | 
  •  

Вопрос

Я перебираю хэш-карту (см. мой предыдущий вопрос для получения более подробной информации) и построения строки, состоящей из данных, содержащихся на Карте.Для каждого элемента у меня будет новая строка, но для самого последнего элемента мне не нужна новая строка.Как я могу этого добиться?Я думал, что мог бы каким-то образом проверить, является ли запись последней или нет, но я не уверен, как на самом деле это сделать.

Спасибо!

Это было полезно?

Решение

Измените свой мыслительный процесс с "добавляйте разрыв строки все, кроме последнего раза" на "добавляйте разрыв строки все, кроме первого раза".:

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());
}

Другие советы

один метод (с извинениями перед Джоном Скитом за заимствование части его 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);

Обязательные извинения и благодарность Джону и Джоэлу за "заимствование" из их примеров.

Обычно для подобных вещей я использую apache-commons-lang StringUtils#присоединиться.Хотя написать все эти виды утилит на самом деле не сложно, всегда лучше повторно использовать существующие проверенные библиотеки. Apache-общий доступ здесь полно подобных полезных вещей!

Если вы используете iterator вместо for...каждый ваш код может выглядеть следующим образом:

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());
}

(Приношу извинения и благодарю Джона и Джоэла за "заимствование" из их примеров.)

Одним из решений является создание пользовательской оболочки для 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();

У этого действительно есть некоторые недостатки:

  • Написание кода, который обычно не ориентирован на "домен / бизнес"
  • Не используя стандартное решение с открытым исходным кодом, такое как:StringUtils.присоединяйтесь
  • Вынужден поддерживать класс, который обертывает класс JDK, который является окончательным и, следовательно, требует долгосрочных обновлений.

Я выбрал StringUtils.решение join для перебора коллекций и даже создания шаблонов облегченных методов сборки в коде.

Предполагая, что ваш цикл foreach проходит через файл по порядку, просто добавьте новую строку к каждой строке и удалите последнюю новую строку при завершении цикла.

Не уверен, что это лучший способ, но это самый простой способ сделать:

перебирайте все значения и добавляйте обычным образом в stringbuffer .Затем сделайте что-то вроде этого

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

Вот где пригодился бы метод join, дополняющий split , потому что тогда вы могли бы просто объединить все элементы, используя новую строку в качестве разделителя, и, конечно, он не добавляет новую строку в конец результата;вот как я делаю это на различных языках сценариев (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());
}

Разделитель печатается в пустой строке при его первом использовании и разделитель при всех последующих использованиях.

Ha!Благодаря этот пост Я нашел другой способ сделать это:

public static class Extensions
{
    public static string JoinWith(this IEnumerable<string> strings, string separator)
    {
        return String.Join(separator, strings.ToArray());
    }
}

Конечно, сейчас это на C #, и Java (пока) не будет поддерживать метод расширения, но вы должны иметь возможность адаптировать его по мере необходимости — главное, это использование String.Join во всяком случае, и я уверен, что у java есть какой-то аналог для этого.

Также обратите внимание, что это означает выполнение дополнительной итерации строк, потому что вы должны сначала создать массив, а затем выполнить итерацию по нему, чтобы построить свою строку.Кроме того, вы будет создайте массив, где с помощью некоторых других методов вы могли бы обойтись без IEnumerable, который одновременно содержит только одну строку в памяти.Но мне действительно нравится дополнительная ясность.

Конечно, учитывая возможности метода расширения, вы могли бы просто абстрагировать любой другой код в метод расширения.

Позвольте библиотекам сделать это за вас.

import com.sun.deploy.util.StringUtils;

как и многие другие, есть StringUtils, в котором есть метод join .Вы можете сделать это в одной строке:

StringUtils.join(list, DELIMITER);

Но для большего контекста, вот как вы могли бы сделать это с помощью hashmap.

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"));
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top