【问题标题】:convert to capital letter using java 8 stream使用java 8流转换为大写字母
【发布时间】:2018-11-09 21:53:33
【问题描述】:

我有一个字符串列表,例如“出租车或公共汽车司机”。我需要将每个单词的第一个字母转换为大写字母,除了单词 "or" 。有没有什么简单的方法可以使用 Java 流来实现这一点。 我已经尝试过 Pattern.compile.splitasstream 技术,我无法将所有拆分的标记连接回来以形成原始字符串 任何帮助将不胜感激。如果有任何机构需要,我可以在这里发布我的代码。

【问题讨论】:

    标签: java java-8 java-stream


    【解决方案1】:

    您需要正确的模式来标识必须进行更改的位置,当您想使用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());
    

    也可以将 lambda 表达式 s -&gt; capitalizeWords(s) 替换为 ContainingClass::capitalizeWords 形式的方法引用。

    【讨论】:

    • 哦,该死的,正要以接近的模式点击提交:|
    • 嗨#Holger,解决方案的第一部分没有按预期工作,它没有转换为大写。
    • 或者,用java9的Matcher.replaceAllFIRST_WORD_CHAR_BUT_NOT_OR.matcher(phrase).replaceAll(mr-&gt;mr.group().toUpperCase())
    • @PhilipPuthenvila 正则表达式中有错字,它查找的是大写字母而不是小写字母。我已经修好了。谢谢。
    【解决方案2】:

    这是我的代码:

    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"));
    
        }
    }
    

    注意: 您可能还想看看这个SO 帖子关于使用 apache commons-text 库来完成这项工作。

    【讨论】:

    • 这个解决方案适合我的要求
    【解决方案3】:

    将您的字符串拆分为单词,然后将第一个字符转换为大写,然后将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(" "));
    

    【讨论】:

    • 你的理由是?
    • 您对Stream#of 进行了不必要的调用,内部将调用Arrays#stream
    • @Eugene 出于语义原因,我更喜欢Arrays.streamString.split 返回一个数组,Arrays.stream 是流过数组的正确习惯用法。相比之下,Stream.of(…) 是一个 varargs 方法,由于实现了 varargs 的方式(并且为了与 Java 5 之前的代码兼容),它恰好能够接受数组。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-02-04
    • 2015-07-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-07
    相关资源
    最近更新 更多