Ответ 1
В Java 8 вы можете использовать String.join()
следующим образом:
Collection<String> elements = ....;
String result = String.join(", ", elements);
Учитывая список
List<String> l = new ArrayList<String>();
l.add("one");
l.add("two");
l.add("three");
У меня есть метод
String join(List<String> messages) {
if (messages.isEmpty()) return "";
if (messages.size() == 1) return messages.get(0);
String message = "";
message = StringUtils.join(messages.subList(0, messages.size() -2), ", ");
message = message + (messages.size() > 2 ? ", " : "") + StringUtils.join(messages.subList(messages.size() -2, messages.size()), ", and ");
return message;
}
который для l производит "один, два и три". Мой вопрос в том, есть ли стандартный (apache-commons) метод, который делает то же самое?, например
WhatEverUtils.join(l, ", ", ", and ");
Прояснить. Моя проблема не в том, чтобы этот метод работал. Он работает так, как я хочу, он тестировался, и все хорошо. Моя проблема в том, что я не смог найти какой-то модуль, подобный апаху, и который реализует такую функциональность. Что меня удивляет, так как я не могу быть первым, кому это нужно.
Но тогда, возможно, все остальные сделали
StringUtils.join(l, ", ").replaceAll(lastCommaRegex, ", and");
В Java 8 вы можете использовать String.join()
следующим образом:
Collection<String> elements = ....;
String result = String.join(", ", elements);
Как насчет join от: org.apache.commons.lang.StringUtils
Пример:
StringUtils.join(new String[] { "one", "two", "three" }, ", "); // one, two, three
Чтобы иметь "и" или ", и" вы можете просто заменить последнюю запятую.
Мне нравится использовать Гуава для этой цели. Аккуратный и очень полезный:
Joiner.on(",").join(myList)
Этот вид кода был написан снова и снова, и вы должны быть освобождены, реализуя вашу конкретную логику реализации.
Если вы используете Maven, при этом зависимость:
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>28.1-jre</version>
</dependency>
У него также есть куча других замечательных интересных функций!
Это приведет к появлению строки "один, два и три".
List<String> originalList = Arrays.asList("one", "two", "three");
Joiner.on(", ")
.join(originalList.subList(0, originalList.size() - 1))
.concat(", and ")
.concat(originalList.get(originalList.size() - 1));
С помощью Java 8 вы можете использовать потоки со столярами.
Collection<String> strings;
...
String commaDelimited = strings.stream().collect(Collectors.joining(","));
// use strings.parallelStream() instead, if you think
// there are gains to be had by doing fork/join
Другие ответы говорят о "замене последней запятой", что небезопасно, если последний термин содержит запятую.
Вместо использования библиотеки вы можете просто использовать одну (хотя и длинную) строку кода JDK:
public static String join(List<String> msgs) {
return msgs == null || msgs.size() == 0 ? "" : msgs.size() == 1 ? msgs.get(0) : msgs.subList(0, msgs.size() - 1).toString().replaceAll("^.|.$", "") + " and " + msgs.get(msgs.size() - 1);
}
Смотрите живую демонстрацию этого кода, обрабатывающего все случаи краев.
FYI, здесь более читаемый двухстрочный слой:
public static String join(List<String> msgs) {
int size = msgs == null ? 0 : msgs.size();
return size == 0 ? "" : size == 1 ? msgs.get(0) : msgs.subList(0, --size).toString().replaceAll("^.|.$", "") + " and " + msgs.get(size);
}
Чтобы создать грамматический вывод на английском языке, необходимо учитывать три случая при объединении списка строк:
"А"
"A и B"
"A, B и C.
Это может быть выполнено с использованием стандартных Java или Guava, как показано ниже. Решения в основном одинаковы и только до того, что вы хотите использовать.
import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableList;
import org.junit.Test;
import java.util.List;
import static org.junit.Assert.assertEquals;
public class JoinListTest {
@Test
public void test_join() {
// create cases (don't need to use ImmutableList builder from guava)
final List<String> case1 = new ImmutableList.Builder<String>().add("A").build();
final List<String> case2 = new ImmutableList.Builder<String>().add("A", "B").build();
final List<String> case3 = new ImmutableList.Builder<String>().add("A", "B", "C").build();
// test with standard java
assertEquals("A", joinListGrammaticallyWithJava(case1));
assertEquals("A and B", joinListGrammaticallyWithJava(case2));
assertEquals("A, B, and C", joinListGrammaticallyWithJava(case3));
// test with guava
assertEquals("A", joinListGrammaticallyWithGuava(case1));
assertEquals("A and B", joinListGrammaticallyWithGuava(case2));
assertEquals("A, B, and C", joinListGrammaticallyWithGuava(case3));
}
private String joinListGrammaticallyWithJava(final List<String> list) {
return list.size() > 1
? String.join(", ", list.subList(0, list.size() - 1))
.concat(String.format("%s and ", list.size() > 2 ? "," : ""))
.concat(list.get(list.size() - 1))
: list.get(0);
}
private String joinListGrammaticallyWithGuava(final List<String> list) {
return list.size() > 1
? Joiner.on(", ").join(list.subList(0, list.size() - 1))
.concat(String.format("%s and ", list.size() > 2 ? "," : ""))
.concat(list.get(list.size() - 1))
: list.get(0);
}
}
Я не знаю ни одного Apache String, который может поддерживать добавление and
в объединенную строку.
Здесь непроверенный код, который будет делать то, что вы просили:
public static String join(String separator, List<String> mList, boolean includeAndInText) {
StringBuilder sb = new StringBuilder();
int count = 0;
for (String m: mList) {
if (includeAndInText && (count + 1 != mList.size())) {
sb.append (" and ");
}
sb.append(m);
count++;
if (count < mList.size()) {
sp.append(separator);
}
}
return sb.toString();
}