skip to Main Content

I have a string containing multiple json, like this:

{"token":" kann","finish":false}{"token":" ich","finish":false}

I want to parse these mutliple Jsons, so I need to split them from the string.

I could search for }{ occurances and split there. But I am not sure if this would be best practice. Is there a canonical way to do this?

4

Answers


  1. Since it’s not valid JSON in and of itself, there’s no "standard" approach.

    So: this fails if you have a more complex object, like

        {"token":" kann","finish":false, "pizza": [{"topping": "pepperoni"**}, 
    {**"topping": "cheese"]}{"token":" kann","finish":false, "pizza": [{"topping": "pepperoni"**},{**"topping": "cheese"]}
    

    If would be better if you could get your JSON like this:

    [{"token": " kann", "finish": false},{"token": " ich","finish": false}]
    

    That would parse directly, no additional manipulation needed. If you were on my team, that’s what I would push toward.

    Without knowing how you’re getting the JSON, and just taking it at face value, if your string is predictable, the same spacing every time, and will NEVER change format (never trust input you’re not directly in charge of), then splitting as you’ve suggested is about all you can do, just understand that if anything ever changes, your code will break.

    Login or Signup to reply.
  2. Although @Winter Dev makes a sensible suggestion in his answer here to prevent this problem in the first place, I’d still like to provide an answer to the asked question.

    A more sensible way would be a stack-based search. You can read the string from the very first { character up until a matching }.

    Here’s the pseudocode:

    for (char, index) in line
       stack = new stack
       if (char equals '{')
          stack.push(char)
       if ((char equals '}'))
          if (stack.length == 1)
             // stack length is 1 so we must match the first {
             // this means this is the end of our first JSON
             print(index of end of json)
          else
             // forget about inner {}
             stack.pop()
    

    Note that this fails when an unmatched { or } is present, i.e. when you have incorrect JSON syntax or when a { is listed as a normal character in a string somewhere. You would have to consider such edge cases in a real implementation.

    Login or Signup to reply.
  3. As suggested by @Winter Dev, you could format your JSON to have an array.

    Example:

    import 'dart:convert';
    
    void main() {
      String oldJSON = '{"token":" kann","finish":false}{"token":" ich","finish":false}';
    
      String newJSON = "[" + oldJSON.replaceAll("}{", "},{") + "]"; 
      List<dynamic> elements = json.decode(newJSON);
      
      print("Elements:");
      for (var elem in elements) {
        print(elem);
      }
    }
    

    Output:

    Elements:
    {token:  kann, finish: false}
    {token:  ich, finish: false}
    

    NB: as @Daniels118 pointed out in the comment section, this solution would obviously add the commas if a pair of }{ brackets is present in a string inside the JSON, thus corrupting it.

    Login or Signup to reply.
  4. This is the way: implement a minimal json parser to skip control chars when they are within strings, and split when the structure depth comes to zero.

    I have added a { within one of the strings to show how strong is the algorithm.

    void main() {
      String data = '{"token":" ka{nn","finish":false}{"token":" ich","finish":false}';
      var inString = false;
      var escape = false;
      var depth = 0;
      var subJson = '';
      for (var i = 0; i < data.length; i++) {
        var c = data[i];
        if (inString) {
          if (escape) {
            escape = false;
          } else if (c == '\') {
            escape = true;
          } else if (c == '"') {
            inString = false;
          }
        } else {
          if (c == '"') {
            inString = true;
          } else if (c == '{' || c == '[') {
            depth++;
          } else if (c == '}' || c == ']') {
            depth--;
          }
        }
        subJson += c;
        if (depth == 0) {
          print(subJson + "n");
          subJson = '';
        }
      }
    }
    

    Output:

    {"token":" ka{nn","finish":false}
    {"token":" ich","finish":false}
    

    Does not work if the json is invalid. If you want it more robust you can make it your own.

    P.S. this is a naive implementation just for demo purposes, it is extremely inefficient in case of long jsons because of the single char concatenations. It can be speed up a lot by holding the start and end index of the subJson, and then use a single substring extraction.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search