PerlMonkey22 has asked for the wisdom of the Perl Monks concerning the following question:

I´m making a project where my script tests our JSON API. I have one functional version:
use strict; use warnings; use JSON; use JSON::Parse 'parse_json'; use Data::Dumper qw(Dumper); my $content = `curl --silent -k -u admin:pass https://url/api/v2/GetDe +viceInfo?$ARGV[0]`; my $decoded_json = decode_json($content); my $data = Dumper $decoded_json; foreach my $line($data) { print "$line\n"; }
The second part is to get the same output with all the Objects and Arrays highlighted but without any modules. I´ve got this so far:
my $content = `curl --silent -k -u admin:pass https://url/api/v2/GetDe +viceInfo?$ARGV[0]`; $content =~ tr/"/ /; $content =~ tr/,/\n/; print "$content\n";
The $content variable is an JSON API. The whole JSON is an Array, with objects in it, and other Arrays in those objects. The [] are for the Arrays and {} for Objects. Current Output of my script is:
"device":[{ host_info: { engine_id: null name: null host_group_info: { name: null remarks: null id: 0} ...
The objective is to make it look like below:
"device": [{ "host_info": { "engine_id": null, "name": null, "host_group_info": { "name": null, "remarks": null, "id": 0 } } ...
I strugle to implement a tab after each opening bracket and reverse the tab after each closing bracket. Maybe someone has got even a simpler solution than that?

Replies are listed 'Best First'.
Re: Regex replacing Brackets with horizontal tabs and newliners
by choroba (Cardinal) on Sep 07, 2022 at 11:04 UTC
    > without any modules.

    You're going to write a JSON parser yourself. Without a parser, it's very hard to guess whether a newline should go after a comma - it might be part of a string or key, similarly brackets might appear in strings and commas. A double quote closes a string, but not if it's preceded by a backslash, unless the backslash is preceded by another backslash, etc.

    Good luck.

    map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]
Re: Regex replacing Brackets with horizontal tabs and newliners
by marto (Cardinal) on Sep 07, 2022 at 10:50 UTC
Re: Regex replacing Brackets with horizontal tabs and newliners (updated)
by AnomalousMonk (Archbishop) on Sep 07, 2022 at 11:26 UTC

    Note that the following does not in any way encode, decode, parse or validate JSON syntax. It just naively pretty-prints JSON-ish stuff that is assumed valid. I'm sure there are modules that would do a much better, more reliable job of this, but you specify that, for some reason, you do not want to use any modules. (Update: Note in particular choroba's comments on this.)

    Win8 Strawberry 5.8.9.5 (32) Wed 09/07/2022 7:13:21 C:\@Work\Perl\monks >perl use strict; use warnings; use Data::Dump qw(dd); # for debug my $j = <<'EOJ'; "device": [{"host_info" : { "engine_id":null , "name": null ,"host_group_info" :{"name":null,"remarks":null , "id" : 0 } }} ] EOJ print ">>\n$j<< \n"; my $dent = ' '; my $n_dent = 0; my %pretty = ( '{' => sub { my $d = $dent x ++$n_dent; return qq{$_[0]\n$d}; }, '}' => sub { my $d = $dent x --$n_dent; return qq{\n$d$_[0]}; }, ',' => sub { my $d = $dent x $n_dent; return qq{$_[0]\n$d}; }, ':' => sub { my $d = $dent x $n_dent; return qq{$_[0] }; }, ); $j =~ s{ \s* ([{},:]) \s* } { $pretty{$1}->($1) }xmsge; print ">>\n$j<< \n"; ^Z >> "device": [{"host_info" : { "engine_id":null , "name": null ,"host_group_info" :{"name":null,"remarks":null , "id" : 0 } }} ] << >> "device": [{ "host_info": { "engine_id": null, "name": null, "host_group_info": { "name": null, "remarks": null, "id": 0 } } }] <<

    Update: Here's a variation that handles double-quoted strings a little better. All the old caveats still apply.

    Win8 Strawberry 5.30.3.1 (64) Wed 09/07/2022 8:14:56 C:\@Work\Perl\monks >perl use 5.010; # needs \K regex extension use strict; use warnings; # use Data::Dump qw(dd); # for debug my $j = <<'EOJ'; "device\"": [{"host_in}fo" : { "eng{ine_id,":null , "name:": null ,"host_group_info\\" :{"na\"me":null,"\"remarks":null , "id" : 0 } "{[:," : "weird", "crazy" : "[{,:" }} ] EOJ print ">>\n$j<< \n"; use constant DENT => ' '; my $n_dent = 0; my %pretty = ( '{' => sub { my $d = DENT x ++$n_dent; return "$_[0]\n$d"; }, '}' => sub { my $d = DENT x --$n_dent; return "\n$d$_[0]\n$d"; }, ',' => sub { my $d = DENT x $n_dent; return "$_[0]\n$d"; }, ':' => sub { my $d = DENT x $n_dent; return "$_[0] "; }, ); my $rx_d_quote = qr{ " [^\\"]* (?: \\. [^\\"]*)* " }xms; $j =~ s{ $rx_d_quote? \K \s* ([{},:]) \s* } { $pretty{$1}->($1) }xmsge; print ">>\n$j<< \n"; ^Z >> "device\"": [{"host_in}fo" : { "eng{ine_id,":null , "name:": null ,"host_group_info\\" :{"na\"me":null,"\"remarks":null , "id" : 0 } "{[:," : "weird", "crazy" : "[{,:" }} ] << >> "device\"": [{ "host_in}fo": { "eng{ine_id,": null, "name:": null, "host_group_info\\": { "na\"me": null, "\"remarks": null, "id": 0 } "{[:,": "weird", "crazy": "[{,:" } } ] <<


    Give a man a fish:  <%-{-{-{-<

Re: Regex replacing Brackets with horizontal tabs and newliners
by GrandFather (Saint) on Sep 07, 2022 at 11:35 UTC
      The issue here is, I have a working script using CPAN, yet my manager said its way too easy and I should try achive the same thing by using only regex

        Well it's one thing to try this as an exercise, for most things significant effort has been spent on the non-trivial task of catering for everything when parsing, same goes for HTML, XML etc...

        "As a learning" exercise is about the only valid reason to eschew CPAN I can think of. As a learning exercise it is especially useful if it serves to contrast the benefit of using CPAN compared to rolling your own solution. It is even more useful if the learning exercise also involves creating even a tiny fraction of the testing that CPAN modules are subject to.

        If that is the objective of your manager and you have been given time to engage in this learning exercise then you have a truly enlightened manager!

        Optimising for fewest key strokes only makes sense transmitting to Pluto or beyond
        I have a working script using CPAN, yet my manager said its way too easy and I should try achive the same thing by using only regex

        That's plain stupid and a waste of time. If your manager regularly behaves like this, search for another job. It's just not worth wasting your time this way. Been there, done than.

        Imagine a carpenter's manager telling him to put way all tools except for a rock with a sharp edge. Sure, you could build a house with that rock. But using modern tools is less risky and way faster.

        Alexander

        --
        Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)

        NIH is a cancer. Unless you picked one of the few clinkers from the CPAN, and I don’t think there are any JSON modules that fit that particular bill. What afoken and Fletch said**10.