如何解析包含文本限定符的字符串?

3

我该如何解析字符串 String str = "abc, \"def,ghi\"";

以便使输出为

String[] strs = {"abc", "\"def,ghi\""}

即一个长度为2的数组。

我应该使用正则表达式还是Java API或其他开源项目中有任何方法可以让我做到这一点?

编辑

为了给问题提供背景,我正在读取一个文本文件,其中每行都有一个记录列表。每个记录都有由分隔符(逗号或分号)分隔的字段列表。现在我有一个要求,我必须支持文本限定符,就像Excel或Open Office支持的那样。假设我有记录

abc,“def,ghi”

在这个字符串中,,是我的分隔符,而“是我的文本限定符,这样当我解析这个字符串时,我应该得到两个字段abc和def,ghi,而不是{abc,def,ghi}。

希望这清楚地说明我的要求。

谢谢

Shekhar


1
@Burkhard的修改实际上改变了预期结果的要求。你想要{"abc", "def,ghi"}还是{"abc", "\"def,ghi\""} - David Hedlund
@David:实际上,我刚刚将abc更改为"abc",即一个字符串。也许我还应该将"def,ghi"更改为""def,ghi""? - Burkhard
1
@Burkhard:是的,那正是我的观点。当第一个字符串没有引号而第二个字符串有引号时,我们仍然可以假设字符串引用被一致地省略了,并且显示的只是。现在我们真的不能假设任何东西了 =) - David Hedlund
我想要 {"abc", ""def,ghi""}。 - Shekhar
System.out.println(strArray[1]) 的命令行结果应该是什么? - Matt Mitchell
4个回答

5

基本算法并不太复杂:

 public static List<String> customSplit(String input) {
   List<String> elements = new ArrayList<String>();       
   StringBuilder elementBuilder = new StringBuilder();

   boolean isQuoted = false;
   for (char c : input.toCharArray()) {
     if (c == '\"') {
        isQuoted = !isQuoted;
        // continue;        // changed according to the OP comment - \" shall not be skipped
     }
     if (c == ',' && !isQuoted) {
        elements.add(elementBuilder.toString().trim());
        elementBuilder = new StringBuilder();
        continue;
     }
     elementBuilder.append(c); 
   }
   elements.add(elementBuilder.toString().trim()); 
   return elements;
}

那能处理嵌套的转义引号吗? - Matt Mitchell
1
真是太棒了!对于这个问题,我可能会想出更复杂的解决方案:D - David Hedlund
1
还没有,但是(1)我没有看到这样的要求,(2) - 这是一个基本算法。你可以很容易地添加一个“嵌套引用”检测并改变“isQuoted”测试。 - Andreas Dolk
1
@David - 可以引入像 "one, \"two, \\\"three\\\"\"" 这样的语法来允许嵌套引号,但这还不是必需的要求(目前)。 - Andreas Dolk
@Andreas_D:是的,我猜那是真的。但另一件完全不同的事情引起了我的注意:假设字符串没有以逗号结尾,你不需要在返回之前再执行第二个elements.add来添加当前生成器中的内容吗? - David Hedlund
显示剩余3条评论

2

2
我认为第二个字符串没有空格只是偶然的,而不是问题的核心。 - David Hedlund
这个例子可以工作,但是在 "abc, \"def, ghi\"" 这种可能有效的输入上会失败(这只是我的猜测)。 - Andreas Dolk
更好了!现在我们的任何评论都不适用了,因为这是完全不同的答案。我宁愿看到旧答案被删除,然后发布这个新答案。但这只是细节问题。对于这个答案点赞。 - David Hedlund
@David Hedlund - 是的,你可能是对的,但现在无论如何都不重要了。 - Matt Mitchell

0

试试这个 -

 String str = "abc, \"def,ghi\"";
            String regex = "([,]) | (^[\"\\w*,\\w*\"])";
            for(String s : str.split(regex)){
                System.out.println(s);
            }

它对于字符串str = "abc, "def,ghi",jkl"将无法工作。预期输出将是{abc,"def,ghi",jkl}。 - Shekhar

0

尝试:

List<String> res = new LinkedList<String>();

String[] chunks = str.split("\\\"");
if (chunks.length % 2 == 0) {
    // Mismatched escaped quotes!
}
for (int i = 0; i < chunks.length; i++) {
    if (i % 2 == 1) {
        res.addAll(Array.asList(chunks[i].split(",")));
    } else {
        res.add(chunks[i]);
    }
}

这将仅拆分未位于转义引号之间的部分。
如果要去除空格,请调用trim()。

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