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