【问题标题】:Parse JSON-like markup in perl在 perl 中解析类似 JSON 的标记
【发布时间】:2016-01-14 16:34:27
【问题描述】:

老实说,我不确定这是什么标记,虽然我起初使用 JSON,但使用来自 JSON::Parseparse_json 失败:JSON error at line 2, byte 15/1380740: Unexpected character '{' parsing initial state: expecting whitespace: '\n', '\r', '\t', ' ' at ....

这是我解析成哈希的内容:https://steamcdn-a.akamaihd.net/apps/730/scripts/items/items_game.d8a302f03758b99ab65b60b3a4a11d73ca4738bd.txt

我尝试了什么:

use strict;
use warnings;
use LWP::UserAgent;
use JSON::Parse 'parse_json';

my $ua = LWP::UserAgent->new;
my $response = $ua->get( "https://steamcdn-a.akamaihd.net/apps/730/scripts/items/items_game.d8a302f03758b99ab65b60b3a4a11d73ca4738bd.txt" );
if ( $response->is_success ) {
     my $game_items = parse_json( $response->content );
     # ... do stuff
}

我做错了吗?这是 JSON 还是我必须创建一些 hack-ish 解决方案来解析它?

我无法通过“可能已经有你答案的问题”部分找到任何建议,但我认为如果我知道此标记的名称会更容易。

【问题讨论】:

  • 看起来像没有分隔符的 JSON!据我所知,这都是散列——似乎没有任何数组。应该很容易递归解析
  • 如果你阅读Steam Web API documentation你会看到你这里有VDF或者Valve Data Format,你可以得到你的数据通过在 URL 的查询参数中添加 format=json 以 JSON 格式(或 XML)

标签: json perl parsing markup steam-web-api


【解决方案1】:

这将处理您的数据,这有点 hacky,但它可以完成工作!

use strict;
use warnings;
use autodie;

use Data::Dump;
use LWP::Simple qw/ mirror /;

use constant URL    => 'https://steamcdn-a.akamaihd.net/apps/730/scripts/items/items_game.d8a302f03758b99ab65b60b3a4a11d73ca4738bd.txt';
use constant MIRROR => 'steamcdn.txt';

my $data = do {
    mirror URL, MIRROR;
    open my $fh, '<', MIRROR;
    local $/;
    <$fh>;
};

my ($hash, $key);
my @stack;

while ( ) {

    if ( $data =~ / \G \s* " ([^"]*) " /gcx ) {
        if ( defined $key ) {
            $hash->{$key} = $1;
            $key = undef;
        }
        else {
            $key = $1;
        }
    }
    elsif ( $data =~ / \G \s* \{ /gcx ) {
        push @stack, [ $hash, $key ];
        $key = $hash = undef;
    }
    elsif ( $data =~ / \G \s* \} /gcx ) {
        die "Structure unbalanced" if defined $key or @stack == 0;
        my ($parent, $key) = @{ pop @stack };
        $parent->{$key} = $hash;
        $hash = $parent;

    }
    else {
        last;
    }
}

die "Structure unbalanced" if @stack;

dd $hash;

输出

{
  items_game => {
    alternate_icons2        => {
                                 weapon_icons => {
                                   65604    => {
                                                 icon_path => "econ/default_generated/weapon_deagle_hy_ddpat_urb_light",
                                               },
                                   65605    => {
                                                 icon_path => "econ/default_generated/weapon_deagle_hy_ddpat_urb_medium",
                                               },
                                   65606    => {
                                                 icon_path => "econ/default_generated/weapon_deagle_hy_ddpat_urb_heavy",
                                               },
                                   65684    => {
                                                 icon_path => "econ/default_generated/weapon_deagle_aa_flames_light",
                                               },
                                   65685    => {
                                                 icon_path => "econ/default_generated/weapon_deagle_aa_flames_medium",
                                               },
                                   65686    => {
                                                 icon_path => "econ/default_generated/weapon_deagle_aa_flames_heavy",
                                               },
                                   65696    => {
                                                 icon_path => "econ/default_generated/weapon_deagle_so_night_light",
                                               },
                                   65697    => {
                                                 icon_path => "econ/default_generated/weapon_deagle_so_night_medium",
                                               },
                                   65698    => {
                                                 icon_path => "econ/default_generated/weapon_deagle_so_night_heavy",
                                               },
                                   65780    => {
                                                 icon_path => "econ/default_generated/weapon_deagle_aa_vertigo_light",
                                               },
                                   65781    => {
                                                 icon_path => "econ/default_generated/weapon_deagle_aa_vertigo_medium",
                                               },
                                   65782    => {
                                                 icon_path => "econ/default_generated/weapon_deagle_aa_vertigo_heavy",
                                               },
                                   65896    => {
                                                 icon_path => "econ/default_generated/weapon_deagle_hy_mottled_sand_light",
                                               },
                                   65897    => {
                                                 icon_path => "econ/default_generated/weapon_deagle_hy_mottled_sand_medium",
                                               },
                                   65898    => {
                                                 icon_path => "econ/default_generated/weapon_deagle_hy_mottled_sand_heavy",
                                               },
                                   66276    => {
                                                 icon_path => "econ/default_generated/weapon_deagle_am_scales_bravo_light",
                                               },
                                   66277    => {
                                                 icon_path => "econ/default_generated/weapon_deagle_am_scales_bravo_medium",
                                               },
                                   66278    => {

【讨论】:

  • Hacky 确实,虽然这将是一个更简单的任务,但我想不会!
  • 随着解析的进行,这非常简单。只有三个可能的标记:字符串、左大括号和右大括号。我的程序只是检查接下来是哪一个,并在两三行代码中处理每个案例。我使用了一个单独的栈数组来消除嵌套哈希引起的递归
  • 如 cmets 中所述,如果您首先请求 XML 或 JSON,则要简单得多。
  • 您可以使用$data =~ / \G \s+ /xgc 在一个地方处理空格,而不是在每个标记前处理它。
【解决方案2】:
my $file = do { local $/; <> };

my @stack = [];
my %handlers = (
   '"' => sub {
      /\G ([^"]*) " /xgc
         or die("Unterminated \"\n");
      push(@{ $stack[-1] }, $1);
   },
   '{' => sub {
      die("Expected string\n") if @{ $stack[-1] } % 2 == 0;
      push(@stack, []);
   },
   '}' => sub {
      die("Unmatched \"}\"\n") if @stack == 1;
      my $hash = pop(@stack);
      die("Missing value\n") if @$hash % 2 == 1;
      push(@{ $stack[-1] }, { @$hash });
   },
);

my $data;
for ($file) {
   while (1) {
      my $next_char = /\G \s* (\S) /gcx ? $1 : last;
      my $handler = $handlers{$next_char}
         or die("Unrecognized character \"$next_char\"\n");
      $handler->();
   }

   die("Unmatched \"{\"\n") if @stack > 1;
   my $hash = pop(@stack);
   die("Missing value\n") if @$hash % 2 == 1;
   $data = { @$hash };
}

除了比 Borodin 更简单的堆栈和使用调度表而不是长序列的“如果”之外,这个版本还提供了适当的错误检测。这将检测被截断的文档以及不受支持的功能。

【讨论】:

  • 嗨@ikegami,你有这个代码的工作示例和我的示例吗?我现在对 Borodin 的示例有一个类似文件的问题,我猜这是一个不受支持的功能。
  • 出现了一个小错误。固定的。现在可以使用问题中的示例。
猜你喜欢
  • 1970-01-01
  • 2023-03-12
  • 2010-12-05
  • 2013-07-08
  • 1970-01-01
  • 2013-09-16
  • 2012-04-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多