【问题标题】:Split Nested JSON in Java with Regex使用正则表达式在 Java 中拆分嵌套 JSON
【发布时间】:2013-07-28 00:25:51
【问题描述】:

我有一个 JSON 字符串:

{name:"X",age:{dob:"DD MMM",year:YYYY}}

我需要一对Hashtable<String, String>,比如:

name: "X"
age: {dob:"DD MMM",year:YYYY}

我正在使用

string.substring(1,string.length() - 2).split(",");

如何使用正则表达式实现这一点?

【问题讨论】:

  • 使用正则表达式解析 json 几乎总是很糟糕。我建议你改用 JSON 解析库。
  • 使用正则表达式而不是 propper 库来解析 JSON 就像用锤子而不是勺子喝汤,只是工具不正确。
  • 我同意在没有库的情况下解析 JSON 是一项乏味的任务。但是有没有可以实现的逻辑。
  • 你需要一个递归方法。只需解析所有内容,然后检查每一位,看看是否有更多 JSON。如果有则再次调用相同的方法...
  • @BoristheSpider 你能提供一个示例吗

标签: java regex json split


【解决方案1】:

说明

如果您的 JSON 文本没有嵌套超出示例文本中显示的级别,则此表达式将:

  • 捕获属性名称
  • 捕获属性值
  • 将值数组保持在一起,并且只返回顶层

(?:,|\{)?([^:]*):("[^"]*"|\{[^}]*\}|[^},]*)

示例

Live Demo

示例文本

{name:"X",age:{dob:"DD MMM",year:YYYY}}

代码

String sourcestring = "source string to match with pattern";
Pattern re = Pattern.compile("(?:,|\\{)?([^:]*):(\"[^\"]*\"|\\{[^}]*\\}|[^},]*)",Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
Matcher m = re.matcher(sourcestring);

匹配项

[0][0] = {name:"X"
[0][1] = name
[0][2] = "X"

[1][0] = ,age:{dob:"DD MMM",year:YYYY}
[1][1] = age
[1][2] = {dob:"DD MMM",year:YYYY}

【讨论】:

    【解决方案2】:

    以下是如何在 4 行中完成全部操作:

    Map<String, String> map = new HashMap<String, String>();
    String[] parts = json.replaceAll("^\\{|\\}$","").split("\"?(:|,)(?![^\\{]*\\})\"?");
    for (int i = 0; i < parts.length -1; i+=2)
        map.put(parts[i], parts[i+1]);
    

    它的工作原理如下:

    1. 头部和尾部的大括号被移除,因为我们不能轻易将它们分开 - 它们是垃圾
    2. 输入由冒号或逗号分隔,可选地在引号之前/之后(这巧妙地消耗了引号),但前提是下一个大括号不是右大括号(意味着我们不是 在嵌套术语中)
    3. 在拆分结果上循环 2,将名称/值对放入映射中

    这是一些测试代码:

    public static void main(String[] args) throws Exception {
        String json = "{name:\"X\",age:{dob:\"DD MMM\",year:YYYY}}";
        Map<String, String> map = new HashMap<String, String>();
        String[] parts = json.replaceAll("^\\{|\\}$","").split("\"?(:|,)(?![^\\{]*\\})\"?");
        for (int i = 0; i < parts.length -1; i+=2)
            map.put(parts[i], parts[i+1]);
        System.out.println(map.size() + " entries: " + map);
    }
    

    输出:

    2 entries: {age={dob:"DD MMM",year:YYYY}, name=X}
    

    【讨论】:

    • 哇!!这看起来简单多了
    • 嗨@Bohemian你能解释一下正则表达式函数吗?我是正则表达式的新手,很难解密。
    • 不用担心 - 我可以解释,但具体是哪一部分?你想要正则表达式的详细分解吗?顺便说一句,您可以(如果您愿意)“不接受”一个已经接受的答案,然后接受我的;-)
    【解决方案3】:

    这只有在支持递归的情况下才有可能,不幸的是它不在 java 中。

    如果支持递归,这个正则表达式会这样做:(?=({(?&gt;[^{}]|(?1))+}))

    现场演示:http://regex101.com/r/pH7rV8

    【讨论】:

    • 但是就像你说的那样,这在 Java 中是行不通的,为什么要提到它呢?如果他把车钥匙掉在街区中间,你会告诉他在十字路口寻找它们,因为那里的光线更好吗? ;)
    • @AlanMoore:他想要一个正则表达式解决方案,我给了他一个。我认为如果他要切换语言和一般信息,值得一提。
    • @Lindrian,我认为 Alan 的意思是您故意提供了一个不起作用的解决方案。这不完全是问答网站的目的。
    • @Denomales:因为他的问题没有完整的正则表达式答案,除了我的。无论如何,这似乎并不受欢迎,所以我以后不会再这样做了。
    • @Lindrian 我同意没有将 JSON 文本与正则表达式匹配的完整解决方案,但是这里接受的解决方案是一个正则表达式,它将使用 Java 的正则表达式引擎解析 OP 的示例 JSON 文本。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-12-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多