Существует ли существующий служебный метод Java, который может присоединиться к списку строк на и и?

Я ищу что-то, чтобы увеличить функцию функции 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(["Альфа", "Бета", "Омега"]) --> "Альфа, Бета и Омега"


person slk    schedule 21.10.2011    source источник
comment
Если вы ищете что-то, что является частью Sun JDK, его не существует, и Apache Commons является одним из распространенных способов получить эту утилиту (если не считать ее повторной реализации самостоятельно).   -  person wkl    schedule 21.10.2011
comment
это актуально, stackoverflow.com /вопросы/1515437/   -  person bingjie2680    schedule 21.10.2011
comment
@Scorpion Я просмотрел API-интерфейс guava Joiner, но, похоже, он также не поддерживает то, что я хочу из коробки, поэтому, думаю, я запускаю свой собственный.   -  person slk    schedule 21.10.2011
comment
Столяр у вас не работал? Я думаю, что это сработало хорошо для меня. Мой код немного перебарщивает с обработкой пограничных случаев, когда в вашем списке есть пустые/нулевые члены, но мне нравится, что мне не нужно разбивать результат после его построения и застревать в and.   -  person Steve J    schedule 21.10.2011
comment
Также ответил здесь [Метод обратного эффекта java String.split()?] [1] [1]: stackoverflow.com/questions/794248/   -  person Ahmed Masud    schedule 21.10.2011
comment
возможный дубликат Preferred Idiom for Join a Collection of Strings in Java   -  person Raedwald    schedule 17.04.2014


Ответы (3)


[Не удалось корректно обработать конечные и начальные нули/пустые символы. Теперь работает лучше.]

Мой взгляд на это с использованием 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

Мне это нравится, потому что в нем нет сращивания строк. Он разделяет предоставленный список строк, а затем правильно склеивает их вместе, используя правила, основанные на количестве строковых элементов, не возвращаясь назад и не подгоняя «и» постфактум. Я также обрабатываю всевозможные крайние случаи для нулей/пустых значений, появляющихся в начале, конце или середине списка строк. Возможно, вам гарантировано, что этого не произойдет, поэтому вы можете упростить это решение.

[Моя немного отличается от вашей тем, что когда у меня ровно два элемента, я не ставлю запятую после первого элемента и перед "и", а для трех и более запятая ставится перед "и". Это стильная вещь. Легко приспособиться к тому, что вы предпочитаете в отношении того, как должны работать запятые.]

person Steve J    schedule 21.10.2011
comment
Спасибо за это, @steve-j. Я неправильно понял Joiner с первого взгляда, и это был отличный урок о том, как его использовать. Поскольку мне не нужна порядковая запятая (оксфордская запятая, если вы хотите быть претенциозной!), я думаю, что могу немного упростить для своих целей, но это здорово для работы. - person slk; 22.10.2011
comment
Оксфордская запятая? У него есть имя? Я люблю изучать новые вещи! Рад, что смог помочь. - person Steve J; 22.10.2011

Вот хороший способ украсить/настроить только те экземпляры 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 фабричный метод и генерировать их, когда они вам понадобятся.

person Community    schedule 21.10.2011

Если вы не планируете использовать стороннюю библиотеку, вам потребуется написать собственную утилиту.

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();
}
person Jin Kim    schedule 21.10.2011