给出如下列表:
List<String> names = Lists.newArrayList("George", "John", "Paul", "Ringo")
我想将它转换为这样的字符串:
George, John, Paul and Ringo
我可以用相当笨拙的StringBuilder
这样的事情做到这一点:
String nameList = names.stream().collect(joining(", "));
if (nameList.contains(",")) {
StringBuilder builder = new StringBuilder(nameList);
builder.replace(nameList.lastIndexOf(','), nameList.lastIndexOf(',') + 1, " and");
return builder.toString();
}
有更优雅的方法吗?如果需要,我不介意使用库。
注意:
for
循环,但我不是在寻找这样的解决方案答案 0 :(得分:2)
我不确定这是多么优雅,但它确实有效。令人讨厌的部分是你必须反转List
。
List<String> list = Arrays.asList("George", "John", "Paul", "Ringo");
String andStr = " and ";
String commaStr = ", ";
int n = list.size();
String result = list.size() == 0 ? "" :
IntStream.range(0, n)
.mapToObj(i -> list.get(n - 1 - i))
.reduce((s, t) -> t + (s.contains(andStr) ? commaStr : andStr) + s)
.get();
System.out.println(result);
但是,我认为最好的解决方案就是这个。
StringBuilder sb = new StringBuilder();
int n = list.size();
for (String string : list) {
sb.append(string);
if (--n > 0)
sb.append(n == 1 ? " and " : ", ");
}
System.out.println(sb);
它清晰,高效,显然有效。我认为Stream
不适合这个问题。
答案 1 :(得分:2)
正如你已经完成的大部分内容,我将介绍第二种方法&#34; replaceLast&#34;到目前为止,它不在java.lang.String的JDK中:
import java.util.List;
import java.util.stream.Collectors;
public final class StringUtils {
private static final String AND = " and ";
private static final String COMMA = ", ";
// your initial call wrapped with a replaceLast call
public static String asLiteralNumeration(List<String> strings) {
return replaceLast(strings.stream().collect(Collectors.joining(COMMA)), COMMA, AND);
}
public static String replaceLast(String text, String regex, String replacement) {
return text.replaceFirst("(?s)" + regex + "(?!.*?" + regex + ")", replacement);
}
}
您也可以更改分隔符和参数。到目前为止测试您的要求:
@org.junit.Test
public void test() {
List<String> names = Arrays.asList("George", "John", "Paul", "Ringo");
assertEquals("George, John, Paul and Ringo", StringUtils.asLiteralNumeration(names));
List<String> oneItemList = Arrays.asList("Paul");
assertEquals("Paul", StringUtils.asLiteralNumeration(oneItemList));
List<String> emptyList = Arrays.asList("");
assertEquals("", StringUtils.asLiteralNumeration(emptyList));
}
答案 2 :(得分:1)
如果您不介意使用迭代器,则可行:
private static String specialJoin(Iterable<?> list, String sep, String lastSep) {
StringBuilder result = new StringBuilder();
final Iterator<?> i = list.iterator();
if (i.hasNext()) {
result.append(i.next());
while (i.hasNext()) {
final Object next = i.next();
result.append(i.hasNext() ? sep : lastSep);
result.append(next);
}
}
return result.toString();
}
熟悉api的人可能很容易将其重写为收藏家。
答案 3 :(得分:1)
这是使用流API的优雅解决方案:
String nameList = names.stream().collect(naturalCollector(", ", " and "));
Unfortunatley,它取决于这个功能,可以隐藏在某个实用程序类中:
public static Collector<Object, Ack, String> naturalCollector(String sep, String lastSep) {
return new Collector<Object, Ack, String>() {
@Override public BiConsumer<Ack, Object> accumulator() {
return (Ack a, Object o) -> a.add(o, sep);
}
@Override public Set<java.util.stream.Collector.Characteristics> characteristics() {
return Collections.emptySet();
}
@Override public BinaryOperator<Ack> combiner() {
return (Ack one, Ack other) -> one.merge(other, sep);
}
@Override public Function<Ack, String> finisher() {
return (Ack a) -> a.toString(lastSep);
}
@Override public Supplier<Ack> supplier() {
return Ack::new;
}
};
}
...以及此类,它是上述函数中的内部stateholder,但是Collector API想要公开它:
class Ack {
private StringBuilder result = null;
private Object last;
public void add(Object u, String sep) {
if (last != null) {
doAppend(sep, last);
}
last = u;
}
private void doAppend(String sep, Object t) {
if (result == null) {
result = new StringBuilder();
} else {
result.append(sep);
}
result.append(t);
}
public Ack merge(Ack other, String sep) {
if (other.last != null) {
doAppend(sep, last);
if (other.result != null) {
doAppend(sep, other.result);
}
last = other.last;
}
return this;
}
public String toString(String lastSep) {
if (result == null) {
return last == null ? "" : String.valueOf(last);
}
result.append(lastSep).append(last);
return result.toString();
}
}
答案 4 :(得分:0)
如果逗号永远不在值中,那么它就是单行:
String all = names.toString().replaceAll("^.|.$", "").replaceAll(",(?!.*,)", " and");
答案 5 :(得分:-2)
您可以编写自定义函数来添加最后一个分隔符,但是对于它们之间的分隔符,您可以使用StringUtils.join()来完成任务。检查此api
的链接