【问题标题】:How to convert string to hash table in perlperl中如何将字符串转换为哈希表
【发布时间】:2019-03-07 23:47:59
【问题描述】:

我有一个来自 for 循环的字符串:

@file = "/path/window/*_testing_42.csv";


foreach $file(@file) {


$name = $file=~ /(\w*)_testing_42/; #comes from file path
$name = 1$;
print $name; #prints G43B76P90T45

}

我需要这个字符串中的 4 个值(G43、B76、P90、T45)。我想将它们放入散列中,以便我可以具体引用每个值。但是,我尝试实现的哈希表代码无法达到我的预期目的:

 my %hash;



foreach $file(@file) {


    $name = $file=~ /(\w*)_testing_42/; #comes from file path
    $name = 1$;
    print $name; #prints G43B76P90T45



    my($first $second $third $fourth) = $name;
    $hash{"first"} = $first;
    $hash{"second"} = $second;
    $hash{"third"} = $third;
    $hash{"fourth"} = $fourth;

预期输出:

    print $fourth; #should print T45


    print $first; #should print G43
    print $third #should print  P90
}

【问题讨论】:

  • 贴出的代码是不正确的 Perl,它无法运行(即使它是完整的)并且不会产生 cmets 显示的代码。你能发布你的实际代码吗?这对帮助您有很大帮助。
  • 我也不清楚您是要对@files 中的文件名进行模式匹配,还是要打开文件,从中读取数据行并匹配那些线?如果您可以提供匹配的文件名示例或文件内容示例,将会很有帮助。
  • @zdim 代码已编辑/更新...任何帮助将不胜感激
  • @GrantMcLean 我只想能够将字符串 ($name) 中的四个字符串值放入单独的哈希键值中。我更新了文件名的代码。它是全局的,所以它有多个值......
  • 将字符串 'G43B76P90T45' 分解为“字母数字”模式(我从问题中假设的目标):my @parts = 'G43B76P90T45' =~ /([a-zA-Z][0-9]+)/g; 但问题中显示的代码是“非法的”,具有许多基本语法错误,我无法判断上述内容是否真的适用于您的真实代码。再一次:请向我们展示您的实际代码:)

标签: string perl hash


【解决方案1】:

首先您需要将名称分成 4 部分:

my ($first, $second, $third, $fourth) = unpack("(A3)*", $name);

填充哈希

$hash{"first"} = $first;
$hash{"second"} = $second;
$hash{"third"} = $third;
$hash{"fourth"} = $fourth;

并打印哈希

print $hash{"fourth"};

【讨论】:

  • 这假定要提取的模式总是三个字符长;我会陈述这个假设。 (另外,吹毛求疵:它确实“打印哈希”,它打印其中的一个元素。)
  • 简化为:my %hash; @hash{qw( first second third fourth )} = unpack('(A3)*', $name);
【解决方案2】:

如果我正确理解您要做什么,那么@Gever 的回答应该可以解决问题。这是使用正则表达式而不是解包的替代实现:

use 5.010;
use strict;
use warnings;

my @file = glob("/path/window/*_testing_42.csv");

foreach my $file (@file) {
    my($name) = $file =~ /(\w+)_testing_42/;
    my @code = $name =~ /(...)/g;
    say 'Parts found: ', scalar(@code);   # Parts found: 4
    say $code[0];   # G43
    say $code[1];   # B76
    say $code[2];   # P90
    say $code[3];   # T45
}

我使用数组而不是哈希,因为这对我来说更有意义,但如果你真的想要一个哈希,你可以这样做:

foreach my $file (@file) {
    my($name) = $file =~ /(\w+)_testing_42/;
    my %hash;
    @hash{'first', 'second', 'third', 'fourth'} = $name =~ /(...)/g;
    say $hash{first};   # G43
    say $hash{second};  # B76
    say $hash{third};   # P90
    say $hash{fourth};  # T45
}

在这一行:

my($name) = $file =~ /(\w+)_testing_42/;

$name 周围的括号很重要,因为它们强制在列表上下文中评估匹配,这将返回在(\w+) 中捕获的正则表达式部分。如果没有括号,值 1 将分配给 $name,因为有 1 个匹配项。

将值列表分配给散列(称为“散列切片”)中的一系列键的语法有些混乱。 Perl 知道我们将值分配给%hash,因为变量名后面有{,但是我们在变量名之前放置了@,表示我们正在为一个散列片分配多个值。在变量名前使用$ 表示我们正在分配给哈希中的单个值。

我从你的代码中改变的另一件事是我在循环中声明了%hash。这意味着您只能在循环内引用它。如果您在循环之外声明它,则在处理完每个匹配的文件名后,一组值将保持不变,但哈希可能包含来自不同文件名的值,具体取决于上次迭代中存在的字段数。

【讨论】:

  • 我使用(...) 作为匹配任意 3 个字符的简单方法。但是,是的,您也可以将其写为(.{3})([a-zA-Z0-9]{3}) 甚至(\w{3}),即字母、数字和_ 下划线(即:在Perl 变量/标识符名称中有效的字符)。跨度>
猜你喜欢
  • 2017-01-06
  • 1970-01-01
  • 1970-01-01
  • 2010-09-21
  • 2013-02-12
  • 2020-01-02
  • 2012-11-11
  • 2015-07-10
  • 1970-01-01
相关资源
最近更新 更多