按空格分割字符串

4

我需要在Java中按空格分隔单词,因此我使用了.split函数来实现,如下所示:

String keyword = "apple mango ";
String keywords [] = keyword .split(" ");

上述代码运行正常,但唯一的问题是有时我的关键字会包含像"jack fruit""ice cream"这样带双引号的关键字,如下所示。
String keyword = "apple mango \"jack fruit\" \"ice cream\"";

在这种情况下,我需要从关键字数组中获取4个单词,如苹果芒果菠萝蜜冰淇淋。请问有人能告诉我解决方案吗?

2
这可能需要使用正则表达式来检查引号,只是说一下 ;) - AxelH
我的一般感觉是,这种问题实际上可能更适合使用解析器而不是单个正则表达式。 - Tim Biegeleisen
5个回答

4
List<String> parts = new ArrayList<>();
String keyword = "apple mango \"jack fruit\" \"ice cream\"";

// first use a matcher to grab the quoted terms
Pattern p = Pattern.compile("\"(.*?)\"");      
Matcher m = p.matcher(keyword);
while (m.find()) {
    parts.add(m.group(1));
}

// then remove all quoted terms (quotes included)
keyword = keyword.replaceAll("\".*?\"", "")
                 .trim();

// finally split the remaining keywords on whitespace
if (keyword.replaceAll("\\s", "").length() > 0) {
    Collections.addAll(parts, keyword.split("\\s+"));
}

for (String part : parts) {
    System.out.println(part);
}

输出:

jack fruit
ice cream
apple
mango

1
@MuratK。非常抱歉,我的正则表达式匹配有些问题,我最初是在手机上回答这个问题的。现在已经可以工作了。 - Tim Biegeleisen
如果关键词是 String keyword = "\"ice cream\" 192.168.214.125";,那么它不能正确地给出 ice cream192.168.214.125 - Alex Man
1
@AlexMan,我在关键字上添加了额外的trim()来处理这种边缘情况。 - Tim Biegeleisen
@TimBiegeleisen 谢谢 Tim - Alex Man
@AlexMan,我为此添加了另一个修复程序。只需检查是否还有剩余术语可供分割即可。 - Tim Biegeleisen
显示剩余3条评论

3
我会使用正则表达式和两个捕获组来实现。我不知道有其他的方法。
    String keyword = "apple mango \"jack fruit\" \"ice cream\"";
    Pattern p = Pattern.compile("\"?(\\w+\\W+\\w+)\"|(\\w+)");      
    Matcher m = p.matcher(keyword);
    while (m.find()) {
        String word = m.group(1) == null ? m.group(2) : m.group(1);
        System.out.println(word);
    }

我删除了我的解决方案,看到这个解决方案后,我不知道为什么没有考虑使用两个组... - AxelH
虽然楼主可能已经放弃这个帖子了,但这个解决方案是最优雅的。 - Murat Karagöz
如果有人错误地在最后只放了一个双引号,比如 apple mango",会怎么样呢? - Alex Man
如果你需要进行更严格的条件解析,我认为你必须使用重型武器。例如,如果你想将其推向极致并能够检测到这种错误,可以使用JavaCC。正则表达式并没有那样的逻辑。如果你引入了一个扰动,它会表现得很奇怪。 - mprivat
如果关键字是 String keyword = "\"ice cream\" 192.168.214.125";,它不会给出正确的结果,如 ice cream192.168.214.125 - Alex Man

0

这个解决方案可以工作,但我相信它不是最佳的性能/资源。当你有超过两个单词的水果时,它也可以工作。请随意编辑或优化我的代码。

public static void main(String[] args) {
        String keyword = "apple mango \"jack fruit\" \"ice cream\" \"one two three\"";
        String[] split = custom_split(keyword);
        for (String s : split) {
            System.out.println(s);
        }
    }

    private static String[] custom_split(String keyword) {
        String[] split = keyword.split(" ");
        ArrayList<String> list = new ArrayList<>();
        StringBuilder temp = new StringBuilder();
        boolean multiple = false;
        for (String s : split) {
            if (s.startsWith("\"")) {
                multiple = true;
                s = s.replaceAll("\"", "");
                temp.append(s);
                continue;
            }
            if (s.endsWith("\"")) {
                multiple = false;
                s = s.replaceAll("\"", "");
                temp.append(" ").append(s);
                list.add(temp.toString());
                temp = new StringBuilder();
                continue;
            }
            if (multiple) {
                temp.append(" ").append(s);
            } else {
                list.add(s);
            }
        }
        String[] result = new String[list.size()];
        for (int i = 0; i < list.size(); i++) {
            result[i] = list.get(i);
        }
        return result;
    }

0

String.split() 无法做到这一点。您需要为目标令牌设计一个正则表达式,并通过匹配器收集它们,就像这样:

    final Pattern token = Pattern.compile( "[^\"\\s]+|\"[^\"]*\"" );

    List<String> tokens = new ArrayList<>();
    Matcher m = token.matcher( "apple mango \"jack fruit\" \"ice cream\"" );
    while( m.find() )
        tokens.add( m.group() );

0

这将在引号上拆分字符串,然后进一步通过空格拆分偶数成员。

    String keyword = "apple mango \"jack fruit\" \"ice cream\"";
    String splitQuotes [] = keyword.split("\"");

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

    for (int i = 0; i < splitQuotes.length; i++) {
        if (i % 2 == 0) {
            Collections.addAll(keywords, splitQuotes[i].split(" "));
        } else {
            keywords.add(splitQuotes[i]);
        }
    }

只有在引号 "" 内部时,关键字才可以为空。如果您的意思是当两个引号紧挨着时(例如对于 "jack fruit" "ice cream"),它将调用 addAll 并添加空字符串数组,因此不会影响结果。 还有其他我没有看到的情况吗? - Crepi

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