拆分嵌套字符串保持引号

我正在开发一个Java项目,需要嵌套字符串。

对于纯文本的输入字符串如下所示:

这是“一个字符串”,这是“一个”嵌套的“字符串”

结果必须如下:

[0] This [1] is [2] "a string" [3] and [4] this [5] is [6] "a \"nested\" string" 

请注意 ,我希望保留\"序列。
我有以下方法:

 public static String[] splitKeepingQuotationMarks(String s); 

我需要通过给定的规则从给定的s参数创建一个字符串数组,而不使用Java Collection Framework或其衍生物。

我不确定如何解决这个问题。
是否可以使用正则表达式来解决这个问题?

根据评论中的问题进行更新

  • 每个未转义的"关闭未结束" (它们是平衡的)
  • 如果我们想要创建表示它的文字(为了创建代表\我们需要将其写为\\文本),每个转义字符\也必须被转义。

您可以使用以下正则表达式:

 "[^"\\]*(?:\\.[^"\\]*)*"|\S+ 

请参阅正则表达式演示

Java演示 :

 String str = "This is \"a string\" and this is \"a \\\"nested\\\" string\""; Pattern ptrn = Pattern.compile("\"[^\"\\\\]*(?:\\\\.[^\"\\\\]*)*\"|\\S+"); Matcher matcher = ptrn.matcher(str); while (matcher.find()) { System.out.println(matcher.group(0)); } 

说明

  • "[^"\\]*(?:\\.[^"\\]*)*" – 双引号后跟任何0+字符而不是"\[^"\\] )随后是0+序列的任何转义序列( \\. ),后跟除了""之外的任何0+字符
  • | – 要么…
  • \S+ – 一个或多个非空白字符

注意

@ Pshemo的建议 – "\"(?:\\\\.|[^\"])*\"|\\S+" (或"\"(?:\\\\.|[^\"\\\\])*\"|\\S+"会更正确) – 是相同的表达式,但效率低得多,因为它使用的是用*量化的交替组。 由于正则表达式引擎必须测试每个位置,因此该构造涉及更多回溯,并且每个位置有2个概率。 我的基于unroll-the-loop的版本将立即匹配文本块,因此更加快速和可靠。

UPDATE

由于需要String[]类型作为输出,因此您需要分两步执行:计算匹配项,创建数组,然后再次重新运行匹配器:

 int cnt = 0; String str = "This is \"a string\" and this is \"a \\\"nested\\\" string\""; Pattern ptrn = Pattern.compile("\"[^\"\\\\]*(?:\\\\.[^\"\\\\]*)*\"|\\S+"); Matcher matcher = ptrn.matcher(str); while (matcher.find()) { cnt++; } System.out.println(cnt); String[] result = new String[cnt]; matcher.reset(); int idx = 0; while (matcher.find()) { result[idx] = matcher.group(0); idx++; } System.out.println(Arrays.toString(result)); 

查看另一个IDEONE演示

有效的另一种正则表达方法使用负面的后观:“单词”( \w+引用后跟任何前面没有反斜杠的下一个引号 ”,并将你的匹配设置为“全局”(不要第一场比赛的回归)

 (\w+|".*?(? 

在这看到它 。

另一种不使用正则表达式的方法:

 import java.util.ArrayList; import java.util.Arrays; public class SplitKeepingQuotationMarks { public static void main(String[] args) { String pattern = "This is \"a string\" and this is \"a \\\"nested\\\" string\""; System.out.println(Arrays.toString(splitKeepingQuotationMarks(pattern))); } public static String[] splitKeepingQuotationMarks(String s) { ArrayList results = new ArrayList<>(); StringBuilder last = new StringBuilder(); boolean inString = false; boolean wasBackSlash = false; for (char c : s.toCharArray()) { if (Character.isSpaceChar(c) && !inString) { if (last.length() > 0) { results.add(last.toString()); last.setLength(0); // Clears the sb } } else if (c == '"') { last.append(c); if (!wasBackSlash) inString = !inString; } else if (c == '\\') { wasBackSlash = true; last.append(c); } else last.append(c); } results.add(last.toString()); return results.toArray(new String[results.size()]); } } 

输出:

[这是,“一个字符串”,而且,这是“一个”嵌套的“字符串”]