Преобразовать в заглавную букву с использованием потока java 8

У меня есть список таких строк, как «Такси или водитель автобуса». Мне нужно преобразовать первую букву каждого слова в заглавную, кроме слова «или». Есть ли простой способ добиться этого с помощью потока Java. Я пробовал с техникой Pattern.compile.splitasstream, я не мог объединить все разделенные токены обратно, чтобы сформировать исходную строку Любая помощь будет принята с благодарностью. Если кому-то понадобится, я могу разместить здесь свой код.

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
0
6 458
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

Вот мой код:

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class ConvertToCapitalUsingStreams {
    // collection holds all the words that are not to be capitalized
    private static final List<String> EXCLUSION_LIST = Arrays.asList(new String[]{"or"});

    public String convertToInitCase(final String data) {
        String[] words = data.split("\\s+");
        List<String> initUpperWords = Arrays.stream(words).map(word -> {
            //first make it lowercase
            return word.toLowerCase();
        }).map(word -> {
            //if word present in EXCLUSION_LIST return the words as is
            if (EXCLUSION_LIST.contains(word)) {
                return word;
            }

            //if the word not present in EXCLUSION_LIST, Change the case of
            //first letter of the word and return
            return Character.toUpperCase(word.charAt(0)) + word.substring(1);
        }).collect(Collectors.toList());

        // convert back the list of words into a single string
        String finalWord = String.join(" ", initUpperWords);

       return finalWord;
    }

    public static void main(String[] a) {
        System.out.println(new ConvertToCapitalUsingStreams().convertToInitCase("Taxi or bus driver"));

    }
}

Примечание: Вы также можете посмотреть этот пост ТАК об использовании библиотеки apache commons-text для выполнения этой работы.

Это решение подходит для моих требований

Philip Puthenvila 01.06.2018 02:12

Разделите строку на слова, затем преобразуйте первый символ в верхний регистр, затем joining, чтобы сформировать исходную строку:

String input = "Taxi or bus driver";
String output = Stream.of(input.split(" "))
                .map(w -> {
                     if (w.equals("or") || w.length() == 0) {
                         return w;
                     }
                     return w.substring(1) + Character.toUpperCase(w.charAt(0));
                })
                .collect(Collectors.joining(" "));

А твоя причина?

Mạnh Quyết Nguyễn 31.05.2018 09:55

вы делаете ненужный вызов Stream#of, который внутренне вызывает Arrays#stream

Eugene 31.05.2018 10:07

@Eugene Я бы предпочел Arrays.stream по семантическим причинам. String.split возвращает массив, а Arrays.stream - правильная идиома для потоковой передачи по массиву. Напротив, Stream.of(…) - это метод varargs, который может принимать массивы из-за того, как были реализованы varargs (и для совместимости с кодом до Java 5).

Holger 31.05.2018 12:22

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

  • слово начало
  • глядя на символ нижнего регистра
  • не глядя на слово "или"

Объявите это как

static final Pattern WORD_START_BUT_NOT_OR = Pattern.compile("\\b(?=\\p{Ll})(?!or\\b)");

Затем использовать его для обработки токенов просто с потоком и map. Возврат строки работает через .collect(Collectors.joining()):

List<String> input  = Arrays.asList("Taxi or bus driver", "apples or oranges");
List<String> result = input.stream()
    .map(s -> WORD_START_BUT_NOT_OR.splitAsStream(s)
        .map(w -> Character.toUpperCase(w.charAt(0))+w.substring(1))
        .collect(Collectors.joining()))
    .collect(Collectors.toList());
result.forEach(System.out::println);
Taxi or Bus Driver
Apples or Oranges

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

Решение на основе цикла может выглядеть как

private static final Pattern FIRST_WORD_CHAR_BUT_NOT_OR
                           = Pattern.compile("\\b(?!or\\b)\\p{Ll}");

(теперь используется шаблон, который соответствует персонажу, а не смотрит на него)

public static String capitalizeWords(String phrase) {
    Matcher m = FIRST_WORD_CHAR_BUT_NOT_OR.matcher(phrase);
    if (!m.find()) return phrase;
    StringBuffer sb = new StringBuffer();
    do m.appendReplacement(sb, m.group().toUpperCase()); while(m.find());
    return m.appendTail(sb).toString();
}

который, в качестве бонуса, также может обрабатывать символы, охватывающие несколько устройств char. Начиная с Java 9, StringBuffer можно заменить на StringBuilder для повышения эффективности. Этот метод можно использовать как

List<String> result = input.stream()
    .map(s -> capitalizeWords(s))
    .collect(Collectors.toList());

Также возможна замена лямбда-выражения s -> capitalizeWords(s) ссылкой на метод в форме ContainingClass::capitalizeWords.

черт возьми, вот-вот отправится с шаблоном, близким к этому: |

Eugene 31.05.2018 12:33

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

Philip Puthenvila 01.06.2018 02:07

Или с java9 Matcher.replaceAll, FIRST_WORD_CHAR_BUT_NOT_OR.matcher(phrase).replaceAll(mr->mr‌​.group().toUpperCase‌​())

Misha 01.06.2018 07:20

@PhilipPuthenvila была опечатка в регулярном выражении, он искал прописные буквы вместо строчных. Я исправил это. Спасибо.

Holger 01.06.2018 07:46

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