如何在单词和非单词中分割字符串

时间:2018-05-16 05:47:03

标签: java

我正在寻找一种在单词和非单词中分割字符串的优雅方式,其中“单词”由一些正则表达式定义(例如,[a-zA-Z]+)。

输入是一个字符串,输出应该是按顺序排列的单词和非单词子串。例如:

"A! B C, d." -> Arrays.asList("A", "! ", "B", " ", "C", ", ","d", ".")

这是我的看法:

public static String WORD_PATTERN = "[a-zA-Z]+";

public static List<String> splitString(String str) {
    if (str == null) {
        return null;
    }
    Pattern wordPattern = Pattern.compile(WORD_PATTERN);
    Matcher wordMatcher = wordPattern.matcher(str);

    List<String> splitString = new ArrayList<>();

    int endOfLastWord = 0;

    while(wordMatcher.find())
    {
        int startOfNextWord = wordMatcher.start();
        int endOfNextWord = wordMatcher.end();

        if (startOfNextWord > endOfLastWord) {
            String nextNonWord = str.substring(endOfLastWord, startOfNextWord);
            splitString.add(nextNonWord);
        }

        String nextWord = str.substring(startOfNextWord, endOfNextWord);
        splitString.add(nextWord);
        endOfLastWord = endOfNextWord;
    }

    if (endOfLastWord < str.length()) {
        String lastNonWord = str.substring(endOfLastWord);
        splitString.add(lastNonWord);
    }
    return splitString;
}

这感觉不太优雅,我认为应该有一种更好的方法,我只是不知道。

我不打算改进上面的代码,所以请不要参考Codereview。我只发布它以避免“你到目前为止尝试了什么”评论。

我正在寻找一种更简洁,更优雅的方式,理想情况下只使用标准的Java包。

1 个答案:

答案 0 :(得分:2)

您可以使用正则表达式捕获包含可选内容的单词和非单词:

(\w*)(\W*)
  • \ w :[a-zA-Z0-9 _]
  • \ W :[^ a-zA-Z0-9 _]

regex101

的示例

对于每个匹配,取两个捕获组,检查是否捕获了值(长度> 0)并将值添加到列表中。

这给出了一个简单明了的解决方案,如:

public List<String> splitWord(String s){
    List<String> result = new ArrayList<>();
    Pattern p = Pattern.compile("(\\w*)(\\W*)");
    Matcher m = p.matcher(s);

    while(m.find()){
        Optional.of(m.group(1)).filter(str -> !str.isEmpty()).ifPresent(result::add);
        Optional.of(m.group(2)).filter(str -> !str.isEmpty()).ifPresent(result::add);
    }

    return result;
}

注意:Optional是......可选的,但我正在尝试改进自己。它只会检查该组是否具有非空值,并将其添加到列表中。

结果格式化以匹配您的示例

"abc def" -> Arrays.asList("abc", " ", "def")
"a.b. c" -> Arrays.asList("a", ".", "b", ". ", "c")
"a.b." -> Arrays.asList("a", ".", "b", ".")
".aa" -> Arrays.asList(".", "aa")
"." -> Arrays.asList(".")
"a" -> Arrays.asList("a")
".." -> Arrays.asList("..")

以下是ideone

中格式化方法的示例