我有一个非常大的文件,其中包含如下数据:
*1 RES L1 N1 0.32
*22 RES L2 N2 0.64
*100 CAP A1 B1 0.3
*200 CAP A2 B1 0.11
*11 IND K1 K2 0.002
*44 IND X1 Y1 0.00134
... and so on
对于这样的文件(让我们假设上面的数据在一个名为" example.txt"的文件中),我可以轻松地在Perl中创建一个哈希哈希并将这些嵌套的哈希传递给我的其他部分Perl程序:
#!/usr/bin/perl
use strict;
use warnings;
open(FILE,"<", "example.txt") or die "Cannot open file:$!";
if (-f "example.txt") {
while(<FILE>) {
chomp;
if(/^\s*(\S+)\s+(RES|CAP|IND)\s+(\S+)\s+(\S+)\s+(\S+)\s*$/) {
$hoh{$1}{$2}{$3}{$4} = $5;
}
}
close FILE;
}
创建一个哈希哈希(或者更确切地说是字典词典)的类似方法是什么?
我尝试了一小段代码设置下面的dict(不在此处打印完整代码,以便继续关注问题):
...
set dod [dict create]
if [regexp {^\s*(\S+)\s+(RES|CAP|IND)\s+(\S+)\s+(\S+)\s+(\S+)\s*$} $line all id type x y elemValue] {
dict set dod $id $type $x $y $elemValue
}
但这似乎不起作用。我测试了它如下:
foreach id [dict keys $dod] {
if [dict exists $dod "RES"] {
puts "RES KEY EXISTS"
} else {
puts "RES KEY NOT FOUND"
}
}
感谢。
答案 0 :(得分:2)
你的直接问题是正则表达式开头的一个杂散斜杠。
回答这个问题:多键词典 是“哈希哈希”。每个键都会添加一个新级别的词典。
dict set foo aa bb cc 1
在字典中设置成员{cc 1}
,该字典是字典中成员{bb ...}
的值,它是{aa ...}
中成员foo
的值。
如果不想要一个多级字典,但仍需要使用多个键值,则需要执行以下操作:
dict set foo [list aa bb cc] 1
此外,我不知道您的示例中有多少简化,但添加项目的代码可以更好地说明:
if {[lindex $line 1] in {RES CAP IND}} {
dict set dod {*}$line
}
但是如果你想通过例如检查存在“RES”,您需要将其设置为顶级键,您不在示例中(第一列中的项目将成为顶级键)。如上所述初始化,dod
的值为
*1 {RES {L1 {N1 0.32}}} *22 {RES {L2 {N2 0.64}}} *100 {CAP {A1 {B1 0.3}}} *200 {CAP {A2 {B1 0.11}}} *11 {IND {K1 {K2 0.002}}} *44 {IND {X1 {Y1 0.00134}}}
所以你得到一本字典,但dict exists $dod RES
仍然是假的。使用
if {[lindex $line 1] in {RES CAP IND}} {
dict set dod {*}[lrange $line 1 end]
}
(即第一个作为键之后的行中的所有项目,除了最后一个成为值)你得到字典
RES {L1 {N1 0.32} L2 {N2 0.64}} CAP {A1 {B1 0.3} A2 {B1 0.11}} IND {K1 {K2 0.002} X1 {Y1 0.00134}}
您可以测试“RES”的存在。
回到dict-of-dicts
*1 {RES {L1 {N1 0.32}}} *22 {RES {L2 {N2 0.64}}} *100 {CAP {A1 {B1 0.3}}} *200 {CAP {A2 {B1 0.11}}} *11 {IND {K1 {K2 0.002}}} *44 {IND {X1 {Y1 0.00134}}}
您可以通过检查每个子词典来检查“RES”,直到找到具有该键的词典:
set found 0
dict for {key subdict} $dod {
if {[dict exists $subdict RES]} {
set found 1
break
}
}
文档: dict
答案 1 :(得分:1)
不完全相同但有些类似:
set data "*1 RES L1 N1 0.32
*22 RES L2 N2 0.64
*100 CAP A1 B1 0.3
*200 CAP A2 B1 0.11
*11 IND K1 K2 0.002
*44 IND X1 Y1 0.00134
"
set pattern {\s*(\S+)\s+(RES|CAP|IND)\s+(\S+)\s+(\S+)\s+(\S+)?\s*$}
set result [regexp -all -line -inline -- $pattern $data]
if {[llength $result] == 0} {
puts "Not found"
exit 1
}
array set my_data {}
foreach {all ind_0 ind_1 ind_2 ind_3 ind_4} $result {
set my_data($ind_0)($ind_1)($ind_2)($ind_3) $ind_4
}
puts [parray my_data]
示例输出:
my_data(*1)(RES)(L1)(N1) = 0.32
my_data(*100)(CAP)(A1)(B1) = 0.3
my_data(*11)(IND)(K1)(K2) = 0.002
my_data(*200)(CAP)(A2)(B1) = 0.11
my_data(*22)(RES)(L2)(N2) = 0.64
my_data(*44)(IND)(X1)(Y1) = 0.00134