Question

link

Input:
{“firstName”:”John”,”lastName”:”Smith”,”isAlive”:true,”age” :25,”height_cm”:167.6,”address”:{“streetAddress”:”212ndStre et”,”city”:”NewYork”,”state”:”NY”,”postalCode”:”10021-3100” },”phoneNumbers”:[{“type”:”home”,”number”:”212555-1234”},{“ type”:”office”,”number”:”646555-4567”}],”children”:[],”spou se”:null}

Output:

{
  "firstName": "John",
  "lastName": "Smith",
  "isAlive": true,
  "age": 25,
  "height_cm": 167.6,
  "address": {
    "streetAddress": "21 2nd Street",
    "city": "New York",
    "state": "NY",
    "postalCode": "10021-3100"
  },
  "phoneNumbers": [
    {
      "type": "home",
      "number": "212 555-1234"
    },
    {
      "type": "office",
      "number": "646 555-4567"
    }
  ],
  "children": [],
  "spouse": null
}

Solution

Since I did not find anything useful online, I spent an hour writing the following code. These are the things to take into consideration:

  1. Line break after a comma, a left bracket, or prior to a right bracket. A special pattern is “},” - we only do line break once after the comma.

  2. Indentation is important. It’s a little complex cuz we reduce indentation BEFORE printing out a right bracket, but increase indentation AFTER the left bracket.

Code

public void prettify(String input) throws Exception {

    // observation the rules for Json format:
    // 1. each line end with either a { , or }
    // 2. indentation depends on number of brackets
    int len = input.length();
    int left = 0;
    int right = 0;
    int tab = 0;

    while (left < len) {
        // first, advance right pointer to the next line break point
        while (right < len) {
            if (input.charAt(right) == '}' || input.charAt(right) == ']') {
                // first case, if point to a closing bracket
                tab--;
                // indentation should change right away should we find a
                // closing bracket
                if (right + 1 < len && input.charAt(right + 1) != ',') {
                    break;
                }
            } else if (input.charAt(right) == ','
                    || input.charAt(right) == '{'
                    || input.charAt(right) == '[') {
                // second case, break at , or {
                break;
            } else if (right + 1 < len
                    && (input.charAt(right + 1) == '}' || input
                            .charAt(right + 1) == ']')) {
                // third case, break prior to }
                // we need not swap the order of first and third case,
                // because when we found a closing bracket, we need to
                // change indentation right away
                break;
            }
            right++;
        }

        // now print the chars from left pointer to right inclusively
        if (right == len) {
            // end of input
            if (tab != 0) {
                throw new Exception("Json format error!");
            }
            right--;
            // this is for the convenience of printing last line
        }
        printIndentation(tab);
        System.out.println(input.substring(left, right + 1));
        if (input.charAt(right) == '{' || input.charAt(right) == '[') {
            tab++;
        }

        // last, update pointers
        left = ++right;
    }
}

private void printIndentation(int tab) {
    for (int i = 0; i < tab; i++) {
        System.out.print("    ");
    }
}