1

I've got some Javascript code that I need to parse with Perl:

var materials ={
    foo: "bar",
    bar: "baz",
    baz: "foo"
},

I've got this Javascript variable as a string, and I want to match the associative array's body so that I can parse it as JSON with Perl using parse_json(). I cannot figure out what I'm doing wrong with my regular expression:

my ($json_str) = $js_code =~ m/var\smaterials\s=\s+({.+}),/i;

$json_str ends up being uninitialized.

2
  • You might just look at it differently. Right now you are trying to match the json portion of the string. Fixing your regex would be trivial (allow \s* instead of requiring \s+). However, JSON can be more complex than this example. It might be easier to just drop the portion you do not want: s/^[^{]+//. This will strip everything that comes before the first {. Commented Oct 6, 2015 at 4:23
  • 2
    What are you actually trying to do, though? JSON.stringify(materials) will give you real JSON to start with, which makes everything a whole lot easier. Commented Oct 6, 2015 at 4:45

4 Answers 4

2
my ($json_str) = $js_code =~ m/var\smaterials\s=\s*({[\s\S]+?}),/i;

                                                      ^^^^

The problem is . does not match \n by default.So either use [\s\S] or use (?s) the DOTALL flag.

See demo.

https://regex101.com/r/cJ6zQ3/7

or

https://regex101.com/r/cJ6zQ3/8

Sign up to request clarification or add additional context in comments.

2 Comments

Why [\s\S]+ doesn't match '}' also? (and all the rest till the end of the string) Doesn't it need the lazy modifier '?' to work? Like this [\s\S]+?
@GsusRecovery that's d same problem with ur answer.Ur assumption is wrong.it will match } but then it will backtrack as re has to match a } as well.To [\s\S] will backtrack leaving } for } to match.Same with , as well.? is needed only if there are multiple } as then it will match till last }
2

If you can quote the JSON object's keys (like the example below), you could try JSON::Decode::Regexp, the module includes a regex you can use to match a JSON. As a bonus, you get the JSON object loaded as Perl hash. Example code:

use Data::Dump;
use JSON::Decode::Regexp;

my $json_code = <<'_';
var materials ={
    "foo": "bar",
    "bar": "baz",
    "baz": "foo"
},
_

if ($json_code =~ /(\{.+)/s) {
    local $_ = $1;
    local $^R;
    eval { /\A$JSON::Decode::Regexp::FROM_JSON/ } or die "No match";
    die "No match: $@" if $@;
    print "Match: "; dd $_;
}

will print:

Match: { bar => "baz", baz => "foo", foo => "bar" }

Comments

1

Using an exclude group like [^}]+ works as expected also if there are multiple elements:

#!/usr/bin/env perl

my $js_code = <<'__END__';
var previousOne =  {
    pFoo: "pBar",
    pBar: "pBaz",
    pBaz: "pFoo"
},
var materials ={
    foo: "bar",
    bar: "baz",
    baz: "foo"
},
var anotherOne = {
   aFoo: "aBar",
   aBar: "aBaz",
   aBaz: "aFoo"
}
__END__

my ($json_str) = $js_code =~ m/\s*var\s+materials\s*=\s*({[^}]+}),?/;
print "json_str = ${json_str}\n";

I've relaxed some whitespace constraints. You can test it and edit it online here

2 Comments

Why downvote? It's a genuine question. I've tested it (and everyone can do the same executing the perl script in the answer...)
Thank you for point me in the right direction: i've collapsed the default greedy with backtrack behaviour with the greedy possessive behaviour (as [\s\S]++) that not backtrack at all. I've removed the wrong assumption but leave the code cause it works.
0

There's no spaces between the equal sign and the curly bracket, but the pattern requires at least one. Remove the \s+ or change it to \s*.

2 Comments

This does not provide an answer to the question. To critique or request clarification from an author, leave a comment below their post.
@WesFoster How is this not an answer? It is an attempt to solve the problem, and as far as I can tell a correct one. Could you please elaborate on your reasoning here?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.