Attempting to create a JavaScript function for parsing JSON and producing a more aesthetically pleasing string output

While I am familiar with JSON.parse, JSON.stringify, and the npm package prettier, for some reason I still find myself manually handling this task. Let's approach it as a coding interview question without dismissing it due to not using JSON.parse and JSON.stringify as specified.

Given the string:

"['foo', {bar:['baz',null,1.0,2]}]"

I aim to create a function that returns a properly indented JSON object string.

Desired output of the string:

   [
        "foo", 
        {
            "bar":
            [
                "baz", 
                null, 
                1.0, 
                2
            ]
        }
    ]

This is my current attempt:

function printJSON(str) {
    let spaces = [];
    let output = '';

    str.split('').forEach(char => {
        switch(char) {
            case '{':
            case '[':
                spaces.push('    ');
                output += char + '\n' + spaces.join('');
                break;
            case '}':
            case ']':
                spaces.pop();
                output += '\n' + spaces.join('') + char;
                break;
            case ',':
                output += char + '\n' + spaces.join('');
                break;
            default:
                output += char;
                break;
        }
    });

    console.log(output);
    return output
}

However, there is a formatting issue with the output, such as:

[ 
    "foo", 
     { 
        bar:[ // 🚨
            "baz", 
            null, 
            1.0, 
            2 
        ] 
    } 
] 

How can I rectify this format issue? Is there a more elegant or alternative method to achieve this?

Answer №1

Have you experimented with the pretty printing feature of JSON.stringify?

For example:

console.log(JSON.stringify(
  ['foo', { bar: ['baz', null, 1.0, 2 ] } ],
  null,
  4 // Customize indentation with spaces or a string
));

This code will output:

[
    "foo",
    {
        "bar": [
            "baz",
            null,
            1,
            2
        ]
    }
]

If you prefer to use a function that beautifies your code when given as input:

function pretty(string) {
  var object = JSON.parse(string) /* or eval(string) */;
  return JSON.stringify(object, null, 4);
}

Creating your own solution is also an option. You can start by writing -

const input =
  ['foo', {bar:['baz',null,1.1,2]}]

const result =
  toJson(input)

In this snippet, toJson performs a basic type analysis on the input t -

function toJson (t, i = "  ", d = 0)
{ function toString(t)
  { switch (t?.constructor)
    { case Object:
        return [ "{", indent(Object.entries(t).map(([k, v]) => `${k}:\n${toString(v)}`).join(",\n"), i, d + 1), "}" ].join("\n")
      case Array:
        return [ "[", indent(t.map(v => toString(v)).join(",\n"), i, d + 1), "]" ].join("\n")
      case String:
        return `"${t}"`
      case Boolean:
        return t ? "true" : "false"
      default:
        return String(t ?? null)
    }
  }
  return indent(toString(t), i, d)
}

The indent function is defined as follows -

const indent = (s, i = "  ", d = 0) =>
  s.split("\n").map(v => i.repeat(d) + v).join("\n")

To test the toJson function in your browser, expand the following snippet -

function toJson (t, i = "  ", d = 0)
{ function toString(t)
  { switch (t?.constructor)
    { case Object:
        return [ "{", indent(Object.entries(t).map(([k, v]) => `${k}:\n${toString(v)}`).join(",\n"), i, d + 1), "}" ].join("\n")
      case Array:
        return [ "[", indent(t.map(v => toString(v)).join(",\n"), i, d + 1), "]" ].join("\n")
      case String:
        return `"${t}"`
      case Boolean:
        return t ? "true" : "false"
      default:
        return String(t ?? null)
    }
  }
  return indent(toString(t), i, d)
}

const indent = (s, i = "  ", d = 0) =>
  s.split("\n").map(v => i.repeat(d) + v).join("\n")

const input =
  ['foo', {bar:['baz',null,1.1,2]}]

const result =
  toJson(input)

console.log(result)

The desired output is:

[
  "foo",
  {
    bar:
    [
      "baz",
      null,
      1.1,
      2
    ]
  },
  true
]

You can adjust the indentation by providing a second argument, such as a tab character -

const result =
  toJson(input, "\t") // indent using a tab

Alternatively, you can specify a custom number of spaces for indentation -

const result =
  toJson(input, "    ") // indent using four (4) spaces

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

The issue with V-for not functioning arises when creating an array from an external JSON file during

Javascript: // List of Products const productsJSON = 'json/products.json'; // Component - Product Select app.component('product-select', { data() { return { selected: '', options: [] } }, ...

Bring in a 3-dimensional model using JSONLoader in three.js

I'm facing some challenges with incorporating a simple 3D object created in Maya into my Three.js project using JSONLoader. The object consists of various materials (Lambert and Phong) and different colors. I used Maya to create a .obj file, then Ble ...

converting SQL results to JSON format using Python

This question may seem basic, but I need some help with it Currently, I am using SQL Alchemy to fetch the SQL result. with db.connect() as conn: data = conn.execute('''select * from tables''') json_data = json.dumps([ ...

What is the best way to modify JSON data within a file?

To start, I retrieve a JSON array by using the following JavaScript code: $.getJSON("myJSONfile.json") .done(function(data) { myData = data; }); After storing the data in myData, which is a global variable, I proceed to add more informati ...

Transforming the button behavior with jQuery

I have encountered a situation where I am working with code in Twig. {% if followsId == null %} <div id="followUser" class="follow" data-userId="{{ profileUserData.id }}" data-currentUserId="{{ loggedUserData.id }}" data-action="follow"> ...

Adjust the color of a label based on a set threshold in Chart.js

Can anyone help me with my Chart.js issue? Here is a link to the chart: https://i.sstatic.net/RL3w4.gif I am trying to change the color of the horizontal label when it falls between 70.00 - 73.99. Does anyone know if there's a specific option for th ...

Transferring HTML elements between pages

I'm currently working on a project with 4 tabbed views, each housed in separate HTML pages. Each view contains several SVG charts created using d3.js. Now, the client wants to be able to easily cut, paste, or move charts from one tabbed view to anothe ...

Tips for removing fields from a JSON string using .NET MVC Web Api

Within the Get method of my REST API service, public HttpResponseMessage Get() { CustomerRepository lr = new CustomerRepository (); IQueryable<Customer> data = lr.GetCustomer(); var resp = new HttpResponseMessage(HttpStatusCode.OK); resp.C ...

developing a multimedia player using HTML5

I'm attempting to create a dynamic video "collage" that showcases videos with different aspect ratios in a flexible grid layout. Each row should have videos of the same height, while filling up the horizontal space within a container. With known widt ...

Having Trouble Utilizing json_decode to Print Array Values in PHP

stdClass Object ( [free] => 100% δωρεάν [meetsingles] => Γνωρίστε Singles [searchprofiles] => Προφίλ Αναζήτηση ) After decoding a JSON array and displaying it on screen with UTF8 Greek characters, the output appears a ...

How to use Chrome to open multiple windows with mailto links?

I have a website where there is a table of contacts and a button. When the button is clicked, I want to open a mail client for each selected contact. However, in the Chrome web browser, only the first window.open() function is executed due to a limitation ...

Upon refreshing, the user of the React JS application is redirected to a different page

My React JS app utilizes react-router-dom v6 to manage the routes. Everything was working fine until I integrated Firebase Firestore. Now, when I reload the seeker page, it redirects me to the home page instead of staying on the seeker page. This issue is ...

Unable to access child props in parent event handler in React

Currently utilizing React for building a UI, the structure involves a parent component and a child component as shown below: // Child Component var ListItem = React.createClass({ render: function() { var link_details = ( <div> ...

Updating Input Values Dynamically with AJAX and MySQL

I am encountering an issue while attempting to update the values of two textboxes based on the outcome of a query in MySQL database. Here is the error message I receive: Uncaught RangeError: Maximum call stack size exceeded <head> <script ...

Warning: Please use a function instead of Collection#find

I am new to the world of node.js and currently experimenting with discord.js to create a Discord bot. Whenever I use any bot command, I receive a DeprecationWarning in the console. Here is an example: (node:15656) DeprecationWarning: Collection#find: pass ...

Having trouble with Vue and Vuex not returning the correct value in HTML?

I've implemented a navbar that displays specific menu items based on the user's role. Below is the simplified HTML code for the navbar: <v-speed-dial class="speed-dial-container contextual-text-menu" v-if="user && user. ...

How can I make the primary element subtly appear while keeping the secondary one hidden?

setInterval(function () { $(".story1").fadeOut(2000,function(){ $(".story2").fadeIn(2000, function(){ $(".story2").fadeOut(2000) }); }) }); I have created this code. The initial story displayed is story1, an ...

I'm having trouble with my basic routing set up and I'm struggling to understand why it's not working

I'm currently working on a node tutorial and facing some challenges with my routes.js file. Previously, everything was functioning well today as the Node server was able to read the file. However, it seems to be ignoring it now for some unknown reaso ...

What is the best way to convert string dot notation into a nested object structure?

Is there a way to convert a dot notation string such as 'a.b.c.d' into an Object? And if the Object referenced doesn't exist, can we automatically create an empty one? var str = 'a.b.c.d' var obj = {} // Now what? function dotTo ...

Styling components in React using inline styles that are based on JSON values

I'm successfully pulling in JSON data and mapping it within a React component. However, one of the values in the JSON is a HEX code that I want to apply as an inline style for the background color of a div. I have experimented with various methods, b ...