【问题标题】:Perl reading a file and storing each line as variable/valuePerl 读取文件并将每一行存储为变量/值
【发布时间】:2013-02-19 21:59:12
【问题描述】:

我对 perl 还很陌生,但到目前为止,我几乎完成了我需要做的所有事情。

我有一个格式如下的文件:

#IPAAS

@NX_iPaaS_AuthKey=dGstaG9zaGlub0BqcCasdpasdHN1LmNvbTppUGFhUzAw
@NX_iPaaS_href=live/661134565/process/75231

我想将以@NX_iPaaS 开头的每一行读入一个类似的命名变量,例如 @NX_iPaaS_AuthKey 将创建一个名为 $NX_IPAAS_AUTHKEY 的新变量并保存该值,NX_iPaaS_href 将生成一个名为 $NX_IPAAS_HREF 的新变量并带有一个值等等?

--更新--

大家好,我需要对上述解决方案稍作调整......

所以我刚刚发现我正在阅读的文件会有“部分”,例如

----- SECTION=cr 
NX_NTF_PERSISTENT_ID=cr:400017 
NX_NTF_REF_NUM=45 
----- SECTION=cnt 
NX_NTF_PERSISTENT_ID=cnt:F9F342055699954C93DE36923835A182 

您可以看到其中一个变量出现在两个部分中,这(因为我没有“除非定义下一个”)导致之前的值被覆盖。有没有办法在 NX_NTF_ 变量名称前加上每个部分顶部的“section=”行中提供的值?

谢谢

【问题讨论】:

  • 简单状态机:读取一行,找出它是什么,将它存储到适当的地方。起泡、冲洗、重复。
  • 你不想那样做。请改用哈希。
  • 任何例子都会很棒......我已经做了 6 个小时,整天复制粘贴代码无济于事...... :)

标签: perl file variables


【解决方案1】:

最好的做法是使用哈希。

my %hash;
while (<>) {
    chomp;
    my ($key, $value) = split /=/;
    next unless defined $value;
    $hash{$key} = $value;
}

请参阅Why it's stupid to "use a variable as a variable name",了解为什么使用变量变量名不是一个好主意。

【讨论】:

    【解决方案2】:

    您要使用的是哈希。比如:

    use strict;
    use warnings;
    
    my $input = "yourfilename.txt";
    open(my $IN, "<", $input) or die "$0: Can't open input file $input: $!\n";
    
    my %NX_iPaaS_vars;
    
    while (<$IN>) {
        chomp;
        if ($_ =~ /^\@NX_iPaaS/) {
            my ($key, $value) = split(/=/, $_);
            $NX_iPaaS_vars{$key} = $value;
        }
    }
    

    要稍后使用变量,请使用$NX_iPaaS_vars{"name of variable you want"},例如:

    my $href_path = $NX_iPaaS_vars{'@NX_iPaaS_href'};
    # Do something with $href_path here...
    

    【讨论】:

    • uptownnickbrown,感谢您提供的示例,但这会引发错误:在 iPaaS2.pl 第 11 行的字符串中可能意外插值@NX_iPaaS。iPaaS2.pl 第 9 行的语法错误,靠近“ {" 全局符号 "@NX_iPaaS" 需要在 iPaaS2.pl 第 11 行显示包名。iPaaS2.pl 第 15 行出现语法错误,靠近 "}" iPaaS2.pl 的执行因编译错误而中止。
    • 对不起,我只是在没有测试的情况下把它扔进了 SO。正如刚刚编辑的那样,@ 需要在第 11 行的正则表达式中转义,如下所示:\@.
    • 啊在第 6 行还缺少一个右括号 while () {
    • 乐于助人。你真的应该阅读 choroba 链接到的文章 - 很好地解释了为什么你应该用哈希来解决这个问题。
    【解决方案3】:
    #!/usr/bin/perl -w
    use strict;
    
    open(FILE,"test.txt");
    
    my %hash;
    
    foreach (<FILE>)
    {
           if($_=~/@(\S+)=(\S+)/)
           {
                   $hash{$1}=$2;
           }
    
    }
    close(FILE);
    
    # Test Code
    
    foreach (keys %hash)
    {
           printf("%s=%s\n",$_,$hash{$_});
    }
    

    如果变量名是唯一的,这个解决方案效果很好。

    【讨论】:

    • 不要使用-w;缺少use warnings;不要使用裸字文件句柄;不要使用 2-arg open;检查open 的返回值是否有错误;不要使用foreach (&lt;...&gt;);避免&lt; &gt;$_=~ 是多余的; \S+ 可能匹配 =(即您的正则表达式可能是错误的);不要无故使用printf
    • 为什么不 -w ?和 printf ?为什么 $_=~ 是多余的?
    • @Jean 当您use warnings 时,您可以选择性地禁用某些警告类别,例如no warnings 'redefine'。使用它而不是 -w 开关被认为是最佳实践。 Perl 字符串可以插入变量; print "$_=$hash{$_}\n" 是等效的,并且具有较少的间接性。当您需要高级格式(以特定长度切割字符串、对齐、舍入、十六进制……)时,请使用 printf。如果一个正则表达式没有通过=~ 绑定,它默认匹配主题变量$_for(&lt;&gt;) 一次读取所有行; `while()` 一次一行。你的意思是正则表达式/^\@([^=]+)=(.*)$/
    • 谢谢..你能举一个我的正则表达式失败的例子吗?
    • @Jean 问题在于可能包含= 的值。例如。使用email=hello=world@example.com,您的正则表达式会将email=hello 视为字段名称,将world@example.com 视为值。这通常不是用户所期望的。
    猜你喜欢
    • 2019-03-17
    • 1970-01-01
    • 2013-04-12
    • 2017-11-05
    • 2012-08-20
    • 1970-01-01
    • 1970-01-01
    • 2018-02-07
    • 1970-01-01
    相关资源
    最近更新 更多