Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/perl/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Perl 如何通过存储在变量中的索引访问哈希值_Perl_Hash - Fatal编程技术网

Perl 如何通过存储在变量中的索引访问哈希值

Perl 如何通过存储在变量中的索引访问哈希值,perl,hash,Perl,Hash,我正在编写一些代码,以便从网页中提取以JSON格式存储的数据。提取JSON数据并正确解码为哈希 JSON数据的结构非常复杂,我编写了一些辅助代码/函数,可以“遍历”散列并帮助查找散列中感兴趣的值的“索引”(位置) “find”函数返回散列中存储在变量中的数据的“index”(位置) 我试图在其他操作中使用这个变量(存储的“索引”),但迄今为止没有成功 请参阅附带的简单演示代码片段以了解问题的解释 谢谢,, 北极熊 use strict; use warnings; use JSON qw(de

我正在编写一些代码,以便从网页中提取以JSON格式存储的数据。提取JSON数据并正确解码为哈希

JSON数据的结构非常复杂,我编写了一些辅助代码/函数,可以“遍历”散列并帮助查找散列中感兴趣的值的“索引”(位置)

“find”函数返回散列中存储在变量中的数据的“index”(位置)

我试图在其他操作中使用这个变量(存储的“索引”),但迄今为止没有成功

请参阅附带的简单演示代码片段以了解问题的解释

谢谢,, 北极熊

use strict;
use warnings;

use JSON qw(decode_json);

my $index;
my $slice;

my $data = decode_json( join '', <DATA> );

printf "TITLE: %-15s TIME: %5s TIMES: %5s FAVORITE: %s\n",
        $data->{playList}[1]{title},
        $data->{playList}[1]{time},
        $data->{playList}[1]{played},
        $data->{playList}[1]{favorite} ? "yes" : "no";

$index = '{playList}[1]';

$slice = $data{$index};     # does not pass 'use strict' compilation error
$slice = $data->{$index};   # empty slice 
$slice = $data->$index;     # Can't call method "{playList}[1]" on unblessed reference at

printf "TITLE: %-15s TIME: %5s TIMES: %5s FAVORITE: %s\n",
        $slice->{title},
        $slice->{time},
        $slice->{played},
        $slice->{favorite} ? "yes" : "no";

__DATA__
{
    "playList": [
      {
        "title": "Song name 1",
        "time": "3:25",
        "played": "240",
        "favorite": "1"
      },
      {
        "title": "Song name 2",
        "time": "4:12",
        "played": "30",
        "favorite": "0"
      },
      {
        "title": "Song name 3",
        "time": "2:56",
        "played": "85",
        "favorite": "0"
      }
    ]
}
解决方案:


我想向Håkon Hægland和lordadmira表示我的感谢,感谢他们提供的解决方案

use Data::Diver qw/Dive/; # or Data::DPath, etc

# Capture web page, extract data JSON, convert to hash, assign hash ref to $data
my $data = ...; 

# Find index/location in the hash
#my $index = find($data, $value);

my $index = "{contents}{twoColumnBrowseResultsRenderer}{tabs}[0]{tabRenderer}{content}{sectionListRenderer}{contents}[0]{itemSectionRenderer}{contents}[0]{playlistVideoListRenderer}{contents}[0]{playlistVideoRenderer}{title}{accessibility}{accessibilityData}{label}";

$index =~ s/[{\[]//g; # throw away opening brackets

my @index = split /[}\]]/, $index; # split into array on closing brackets

pop @index for 1..8 # 8 levels to back up to

my $slice = Dive( $data, @index ); # extract hash slice of interest

# extract playlist
my $playlist = $slice->{playlistVideoListRenderer}{contents};

# go through playlist and extract information of our interest
foreach ( @$playlist ) {
    my $video = $_->{playlistVideoRenderer};
    printf "%s %8s %s\n",
            $video->{videoId},
            $video->{lengthText}{simpleText},
            $video->{title}{simpleText};
}
use Data::Diver qw/Dive/; # or Data::DPath, etc

my $data = ...;

my $index = "{contents}{twoColumnBrowseResultsRenderer}{tabs}[0]{tabRenderer}{content}{sectionListRenderer}{contents}[0]{itemSectionRenderer}{contents}[0]{playlistVideoListRenderer}{contents}[0]{playlistVideoRenderer}{title}{accessibility}{accessibilityData}{label}";

$index =~ s/[{\[]//g;

my @index = split /[}\]]/, $index;

pop @index for 1..8 # 8 levels to back up to

my $slice = Dive( $data, @index );

my $playlist = $slice->{playlistVideoListRenderer}{contents};


foreach ( @$playlist ) {
    my $video = $_->{playlistVideoRenderer};
    printf "%s %8s %s\n",
            $video->{videoId},
            $video->{lengthText}{simpleText},
            $video->{title}{simpleText};
}
他们都让我参考了
use Data::Dive
,在这个模块的帮助下,我可以从哈希深度备份几层,并提取感兴趣的切片

据了解,通过使用此模块,数组形式的索引更易于使用。由于这个因素,我将更改我的find函数以返回一个索引数组

您可以使用:


问题是代码返回所有键和元素以查找给定元素,而不是元素值本身。最简单的答案是返回对该定位值的引用

... bunch of lookdown code
return \ $this_level->{the_key_I_want}
这样,调用者就可以直接读取/写入叶值

如果要直接使用键和元素列表访问深度值,则必须执行字符串求值。除非您有1000%信任数据,否则不建议这样做,因为某些小丑可以将散列键命名为“system qw{rm-rf/}”

使用这样的列表的正确方法是另一个查找函数,它获取键列表等并逐个访问它们

我有点误解了你原来的问题。只需在代码中编写:

$slice=$data->{playList}[1]

第二次编辑以实际使用$index:

use Data::Diver qw/Dive/; # or Data::DPath, etc
my $data = ...;
my $index = "{contents}{twoColumnBrowseResultsRenderer}{tabs}[0]{tabRenderer}{content}{sectionListRenderer}{contents}[0]{itemSectionRenderer}{contents}[0]{playlistVideoListRenderer}{contents}[0]{playlistVideoRenderer}{title}{accessibility}{accessibilityData}{label}";
my @index = split /[{}[\]]+/, $index;
shift @index;
pop @index for 1..2 # however many levels to back up to
my $slice = Dive( $data, @index );

在评论中,您说您有一个函数可以在JSON数据结构中查找元素,并返回该元素的“路径”,您的问题是查找该元素的更高级别容器


如果这是XML,我将使用XPath进行搜索并找到正确的容器。但别担心,有人开发了一个,有人通过Perl模块提供了这个功能。

我想把我的“谢谢”扩展到Håkon Hægland和lordadmira,感谢他们提供的解决方案

use Data::Diver qw/Dive/; # or Data::DPath, etc

# Capture web page, extract data JSON, convert to hash, assign hash ref to $data
my $data = ...; 

# Find index/location in the hash
#my $index = find($data, $value);

my $index = "{contents}{twoColumnBrowseResultsRenderer}{tabs}[0]{tabRenderer}{content}{sectionListRenderer}{contents}[0]{itemSectionRenderer}{contents}[0]{playlistVideoListRenderer}{contents}[0]{playlistVideoRenderer}{title}{accessibility}{accessibilityData}{label}";

$index =~ s/[{\[]//g; # throw away opening brackets

my @index = split /[}\]]/, $index; # split into array on closing brackets

pop @index for 1..8 # 8 levels to back up to

my $slice = Dive( $data, @index ); # extract hash slice of interest

# extract playlist
my $playlist = $slice->{playlistVideoListRenderer}{contents};

# go through playlist and extract information of our interest
foreach ( @$playlist ) {
    my $video = $_->{playlistVideoRenderer};
    printf "%s %8s %s\n",
            $video->{videoId},
            $video->{lengthText}{simpleText},
            $video->{title}{simpleText};
}
use Data::Diver qw/Dive/; # or Data::DPath, etc

my $data = ...;

my $index = "{contents}{twoColumnBrowseResultsRenderer}{tabs}[0]{tabRenderer}{content}{sectionListRenderer}{contents}[0]{itemSectionRenderer}{contents}[0]{playlistVideoListRenderer}{contents}[0]{playlistVideoRenderer}{title}{accessibility}{accessibilityData}{label}";

$index =~ s/[{\[]//g;

my @index = split /[}\]]/, $index;

pop @index for 1..8 # 8 levels to back up to

my $slice = Dive( $data, @index );

my $playlist = $slice->{playlistVideoListRenderer}{contents};


foreach ( @$playlist ) {
    my $video = $_->{playlistVideoRenderer};
    printf "%s %8s %s\n",
            $video->{videoId},
            $video->{lengthText}{simpleText},
            $video->{title}{simpleText};
}
他们都让我参考了
use Data::Dive
,在这个模块的帮助下,我可以从哈希深度备份几层,并提取感兴趣的切片


据了解,通过使用此模块,数组形式的索引更易于使用。由于这个因素,我将改变我的find函数以返回一个索引数组

Hi,
使用strict--不是一个解决方案,它警告第一种访问形式确实引用了未声明的%data散列($data是对散列的引用)。如果不使用
eval
,就不能在字符串中以这种方式使用perl语法。您可以通过去掉
$index
并只说
$slice=$data->{playList}[1],直接将位置保存为引用。和你更长的“索引”一样。你好,Håkon Hægland,谢谢你的输入,我将调查
使用数据::潜水员
(这对我来说是新的)。不幸的是,您的解决方案没有使用my
$index
变量。请看一下我的便条,看看我要处理什么。JSON结构相当复杂,要在代码中直观地找到所需的片段并不容易,而且需要时间。除此之外,网站可以随时更改JSON结构,代码需要重新编写。在我的find函数中,我只需要指定我感兴趣的块,获取索引,然后提取切片。谢谢代码使用了
qw(playList 1)
,这似乎与
$index
变量
'{playList}[1]
非常相似。如何创建
$index
?也许您可以同样轻松地创建数组
$index=['playList',1]
。由于后者可以传递给
DiveVal()
。实际索引如下所示
my$index=“{contents}{twoColumnBrowseResultsRenderer}{tabs}[0]{tabRenderer}{content}{sectionListRenderer}{contents}[0]{itemssectionRenderer}{contents}[0]{playlingVideoListRenderer}{contents}[0]{playlingVideoListRenderer}{title}{accessibility}{{accessibilityData}{label}”
它比示例中更复杂,但思想是一样的。Polar Bear是的,这很好。没有问题,只需使用
qw(contents TwoColumnBrowseresultsRenderTabs 0…)
相反,您建议我将索引的所有组件放入一个数组中,并将其输入到
DiveVal
?我需要尝试一下,看看会有什么结果。谢谢,谢谢,确实您没有完全理解我的问题。我还有另一个函数(get)它返回对基于已知键的散列切片的引用,这正是您建议的。我最初的问题是,是否可以使用该表单中的索引访问数据?我尝试了不同的方法,可能eval可以这样做,但正如您所提到的,这是不安全的。
data::Dumper
输出散列时,在表单中插入一些结构
$VAR1->{key1}[0]{key2}{key3}…...[8]{keyn}
我想这是某种方式的工作。在我的例子中,我知道我在巨大的散列中寻找什么值,但我还不知道散列中的位置。我编写了“遍历”的函数散列,直到它找到感兴趣的值。函数将索引返回到此值——现在我需要上几层来提取散列切片。为此,我必须手动分析返回的索引,删除部分索引,然后
use Data::Diver qw/Dive/; # or Data::DPath, etc
my $data = ...;
my $index = "{contents}{twoColumnBrowseResultsRenderer}{tabs}[0]{tabRenderer}{content}{sectionListRenderer}{contents}[0]{itemSectionRenderer}{contents}[0]{playlistVideoListRenderer}{contents}[0]{playlistVideoRenderer}{title}{accessibility}{accessibilityData}{label}";
my @index = split /[{}[\]]+/, $index;
shift @index;
pop @index for 1..2 # however many levels to back up to
my $slice = Dive( $data, @index );
use Data::Diver qw/Dive/; # or Data::DPath, etc

my $data = ...;

my $index = "{contents}{twoColumnBrowseResultsRenderer}{tabs}[0]{tabRenderer}{content}{sectionListRenderer}{contents}[0]{itemSectionRenderer}{contents}[0]{playlistVideoListRenderer}{contents}[0]{playlistVideoRenderer}{title}{accessibility}{accessibilityData}{label}";

$index =~ s/[{\[]//g;

my @index = split /[}\]]/, $index;

pop @index for 1..8 # 8 levels to back up to

my $slice = Dive( $data, @index );

my $playlist = $slice->{playlistVideoListRenderer}{contents};


foreach ( @$playlist ) {
    my $video = $_->{playlistVideoRenderer};
    printf "%s %8s %s\n",
            $video->{videoId},
            $video->{lengthText}{simpleText},
            $video->{title}{simpleText};
}