是否存在一种Java实用方法,可以将字符串列表用“,”和“and”连接起来?

3
我正在寻找一种增强apache commons join()函数功能的方法,基本上它将执行makePrettyList()函数所做的事情。
public String makePrettyList(List<String> items) {
    String list = org.apache.commons.lang.StringUtils.join(items, ", ");
    int finalComma = list.lastIndexOf(",");
    return list.substring(0, finalComma) + " and" + list.substring(finalComma + 1, list.length());
}

makePrettyList(["Alpha", "Beta", "Omega"]) --> "Alpha, Beta 和 Omega"


2
如果你正在寻找Sun JDK的一部分,那么它并不存在,而Apache Commons是获取此实用程序的常见方法之一(除了自己重新实现它)。 - wkl
请提供类似于PHP中的join函数的Java数组函数。以下是相关信息:https://dev59.com/onI_5IYBdhLWcg3wHvU5 - bingjie2680
@Scorpion,我研究了Guava Joiner API,但它似乎也不支持我想要的功能,所以我想自己动手实现。 - slk
连接器对你没用?我觉得它对我很有效。我的代码在处理列表中有空/ null成员的边缘情况时有些过度,但我喜欢它不必在构造结果后拆分并插入“and”。 - Steve J
这里也有答案:Java String.split()的反转效果方法? - Ahmed Masud
可能是Java中连接字符串集合的首选习惯用语的重复问题。 - Raedwald
3个回答

4

[未优雅地处理尾随和前导的null/空值。现在已经更好地工作了。]

我的看法是,使用Google Guava(不是官方的Java包,但非常好用)。我提供这个方法是因为你似乎考虑过使用Joiner,但最终拒绝了它。所以既然你曾经愿意使用Joiner,也许现在你想再次考虑它:

package testCode;

import java.util.List;

import com.google.common.base.Joiner;
import com.google.common.base.Predicate;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;

public class TestClass {

    Joiner joinComma = Joiner.on(", ");
    Joiner joinAndForTwo = Joiner.on(" and ");
    Joiner joinAndForMoreThanTwo = Joiner.on(", and ");

    public String joinWithAnd(List<String> elements) {
        ImmutableList<String> elementsNoNullsOrEmpties = new ImmutableList.Builder<String>()
                .addAll(Iterables.filter(elements, new Predicate<String>() {
                    @Override
                    public boolean apply(String arg0) {
                        return !Strings.isNullOrEmpty(arg0);
                    }
                })).build();

        if (elementsNoNullsOrEmpties.size() == 0) {
            return null;
        } else if (elementsNoNullsOrEmpties.size() == 1) {
            return Iterables.getOnlyElement(elementsNoNullsOrEmpties);
        } else if (elementsNoNullsOrEmpties.size() == 2) {
            return joinAndForTwo.join(elementsNoNullsOrEmpties);
        } else {
            final List<String> leadingElements = elementsNoNullsOrEmpties
                    .subList(0, elementsNoNullsOrEmpties.size() - 1);
            final String trailingElement = elementsNoNullsOrEmpties
                    .get(elementsNoNullsOrEmpties.size() - 1);
            return joinAndForMoreThanTwo.join(joinComma.join(leadingElements),
                    trailingElement);
        }
    }
}

还有测试驱动程序:

package testCode;

import java.util.List;

import com.google.common.collect.Lists;

public class TestMain {

    static List<String> test1 = Lists.newArrayList();
    static List<String> test2 = Lists.newArrayList("");
    static List<String> test3 = Lists.newArrayList("a");
    static List<String> test4 = Lists.newArrayList("a", "b");
    static List<String> test5 = Lists.newArrayList("a", "b", "c", "d");
    static List<String> test6 = Lists.newArrayList("a", "b", "c", null, "d");
    static List<String> test7 = Lists.newArrayList("a", "b", "c", null);
    static List<String> test8 = Lists.newArrayList("a", "b", "", "", null, "c",
            null);
    static List<String> test9 = Lists.newArrayList("", "a", "b", "c", null);
    static List<String> test10 = Lists.newArrayList(null, "a", "b", "c", null);

    public static void main(String[] args) {
        TestClass testClass = new TestClass();

        System.out.println(testClass.joinWithAnd(test1));
        System.out.println(testClass.joinWithAnd(test2));
        System.out.println(testClass.joinWithAnd(test3));
        System.out.println(testClass.joinWithAnd(test4));
        System.out.println(testClass.joinWithAnd(test5));
        System.out.println(testClass.joinWithAnd(test6));
        System.out.println(testClass.joinWithAnd(test7));
        System.out.println(testClass.joinWithAnd(test8));
        System.out.println(testClass.joinWithAnd(test9));
        System.out.println(testClass.joinWithAnd(test10));
    }
}

输出结果:

null
null
a
a 和 b
a、b、c 和 d
a、b、c 和 d
a、b 和 c
a、b 和 c
a、b 和 c
a、b 和 c

我喜欢这个方法,因为它不使用任何字符串拼接。它将提供的字符串列表分区,然后根据元素数量使用规则正确地将它们粘合在一起,而不是事后再添加"and"。我还处理了所有可能出现的空值/空元素的边界情况。如果您可以保证不会出现这种情况,那么可以简化此解决方案。

[我的方法与您的略有不同,在只有两个元素时,我不在第一个元素后和 "and"之间加逗号,而在三个或更多元素时,在 "and"之前加逗号。这是一种风格问题。您可以根据逗号的工作方式调整到您喜欢的任何方式。]


谢谢你,@steve-j。一开始我对Joiner的理解有误,这是一个很好的教程,教我如何使用它。由于我不需要串行逗号(如果你想要装逼的话,可以称之为牛津逗号!),所以我认为我可以稍微简化一下,以适应我的需求,但这个教程非常棒。 - slk
1
牛津逗号?它有名字吗?我喜欢学习新东西!很高兴能帮忙。 - Steve J

0

如果您不打算使用第三方库,那么您需要编写自己的实用程序。

public List<String> makePrettyList(List<String> items) {
    StringBuilder builder = new StringBuilder();

    for (int i = 0; i < items.size(); i++) { 
        if (i > 0) {
            builder.append(" ");

            if (i == items.size() - 1) {
                builder.append("and ");
            }
            else {
                builder.append(", ");
            }
        }

        builder.append(items.get(i));
    }

    return builder.toString();
}

0

这里有一种不错的方法,可以仅对需要的 List<String> 实例进行装饰/自定义。

import java.util.*;

public class ListUtils
{
    public static void main(final String[] args)
    {
        final List<String> sl = new ArrayList<String>()
        {
            public String toString()
            {
                final StringBuilder sb = new StringBuilder(this.size() * 512);
                final ListIterator<String> li = this.listIterator();
                while (li.hasNext())
                {
                    if (li.nextIndex() == this.size() - 1)
                    {
                        sb.append("and ").append(li.next());
                    }
                    else if (li.nextIndex() == this.size() - 2)
                    {
                        sb.append(li.next()).append(" ");
                    }
                    else
                    {
                        sb.append(li.next()).append(", ");
                    }
                }
                return sb.toString();
            }
        };

        // Test the output  
        sl.add("Alpha");
        sl.add("Beta");
        sl.add("Omega");
        System.out.println(sl.toString());
    }
}

输出结果为

Alpha, Beta and Omega

您可以将这种构造的创建放在一个public static工厂方法中,并在需要时生成它们。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接