【问题标题】:Parsing JavaScript using Perl: getting "undef" from JE->parse使用 Perl 解析 JavaScript:从 JE->parse 获取“undef”
【发布时间】:2019-10-19 19:31:07
【问题描述】:

我有 Javascript 代码,我需要将 javascript 变量解析为 perl 哈希。有没有现成的模块?我尝试了JE::parse()JavaScript::HashRef::Decode,但都没有成功。

预期行为:

use Data::Dumper;
use SomeModule::ParseJSVariables qw/decode_js/;

my $str = qq/
var data = {
    'abc': 1,
    'def' : 2
    'xyz' : { 'foo' : 'bar' }
}
/;

my $res = decode_js($str);
warn Dumper $res; #

# expected result: 
# { 
#   name => 'data', 
#   value => {
#     'abc' => 1,
#     'def' => 2
#     'xyz' => { 'foo' => 'bar' }
#     }
# }


use JE;
my $j = new JE;
my $parsed = $j->parse($str);
warn Dumper $parsed; # undef :(

如果没有现成的模块,如果有人建议正确的正则表达式或解析方法,我会很高兴。

UPD,澄清。我有大约数千行 javascript 代码,我只需要获取在全局范围内明确给出的变量内容,例如 var x = { 'foo' : 'bar' }。其他代码可以跳过解析。

我的环境:

$ perl --version

This is perl 5, version 22, subversion 1 (v5.22.1) built for x86_64-linux-gnu-thread-multi

$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 16.04.5 LTS
Release:    16.04
Codename:   xenial

$ uname -r
4.19.24-041924-generic

【问题讨论】:

  • 关于第 3 方代码或场外资源的问题不在 Stack Overflow 上的主题范围内。检查Where can I ask about “finding a tool, library, or favorite off-site resource?”
  • 您能提供更多上下文/输入示例吗?您是否只需要解析(可能稍微放松)JSON 或完整的 Javascript 代码(带有循环和函数等等)?
  • 不清楚您要达到的目标。例如,当给定代码let a = console.log("hi"), b = a, c = { foo: function (i) { return function () { return i++; }; }(0) }; { let b = 42; console.log(Math.sqrt(b)); } 时,decode_js 会返回什么?
  • 为什么JE::parse 不起作用?
  • @Thilo 首先我无法安装 JE::parse 而不跳过测试。即使我跳过测试并安装它,我也会得到undef 作为结果

标签: javascript perl parsing static-code-analysis


【解决方案1】:

嗯,我有好消息和坏消息,它们是同一个消息 :) 。您的 JS 存在语法错误,因此 JE 根据 the JE docs 返回 undef。具体来说,def 行上缺少 ,。以下测试适用于我:

代码:

use Data::Dumper;

# Note: use q[ ] instead of qq/ /.  q instead of qq so Perl doesn't interpolate
# into the contents, and [ ] instead of / / so that JS comments can appear
# in the block.
my $str = q[
var data = {
    'abc': 1,
    'def' : 2,   // <==== There was a comma missing here!
    'xyz' : { 'foo' : 'bar' }
}
];

use JE;
my $j = new JE;
my $parsed = $j->parse($str);
warn Dumper $parsed;

输出:太大,无法在此处显示 :)。但它确实包括你想要的!

提取输出

这将是一个挑战。希望以下内容可以帮助您入门。

代码:

use Data::Dumper::Compact 'ddc';   # <== for briefer output
use JE;

# Note: use q[ ] instead of qq/ /.  q instead of qq so Perl doesn't interpolate
# into the contents, and [ ] instead of / / so that JS comments can appear
# in the block.
my $str = q[
var data = {
    'abc': 1,
    'def' : 2,   // <==== There was a comma missing here!
    'xyz' : { 'foo' : 'bar' }
}
];

my $j = new JE;
my $parsed = $j->parse($str);
print ddc $parsed->{tree};     # <== {tree} holds the parsed source

输出(带注释):

bless( [
  [
    0,
    118,
  ],
  "statements",
  bless( [
    [
      1,
      118,
    ],
    "var",
    [
      "data",
      bless( [
        [
          12,
          117,
        ],
        "hash",    <== here's where your hash starts
        "abc",     <== 'abc': 1
        1,
        "def",     <== 'def': 2
        2,
        "xyz",     <== 'xyz': nested hash
        bless( [
          [
            98,
            115,
          ],
          "hash",
          "foo",
          "sbar",
        ], 'JE::Code::Expression' ),
      ], 'JE::Code::Expression' ),
    ],
  ], 'JE::Code::Statement' ),
], 'JE::Code::Statement' )

【讨论】:

    【解决方案2】:

    我找到了最简单的解决方案:)

    关键思想是使用JavaScript::V8JavaScript::Any 和模拟console.log 函数在新上下文中执行javascript 代码。

    my $str = qq/
    var data = {
        'abc': 1,
        'def' : 2,
        'xyz' : { 'foo' : 'bar' }
    };
    /;
    
    use Data::Dumper;
    use JavaScript::V8;
    
    sub extract_js_glob_var {
        my ( $code, $var_name ) = @_;
        my $res;
        my $context = JavaScript::V8::Context->new();
        $context->eval($str);
        $context->bind( console_log => sub { $res = @_[0] } );
        $context->eval('console_log('.$var_name.')');
        undef $context;
        return $res;
    }
    
    warn Dumper extract_js_glob_var($str, 'data');  # 'data.xyz' is also supported ;)
    

    【讨论】:

      猜你喜欢
      • 2014-02-09
      • 2014-11-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-03-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多