【问题标题】:Perl advice - Taking in a file and changing contentsPerl 建议 - 接收文件并更改内容
【发布时间】:2011-08-17 23:10:24
【问题描述】:

我有一些关于如何处理我想用 Perl 编写的脚本的建议。基本上我有一个看起来像这样的文件:

  id: 1
  Relationship: ""
  name: shelby
  pet: 1
  color:4

有些关键词,如宠物和颜色,后面有数字。我希望能够获取一个文件并查找这些关键字(其中有 5 个或 6 个),然后将数字更改为该数字对应的单词。也就是说对于关键字“宠物”---> 0 =狗,1 =猫,2 =鱼。对于关键字“颜色”,0 = 红色,1=蓝色,2=紫色,3=棕色,4=白色。脚本应该找到并更改这些数字。目标应该是一个如下所示的输出文件:

      id: 1
      Relationship: ""
      name: shelby
      pet: cat
      color:white

我一直在为如何做到这一点而苦苦挣扎。我在网上查了一下,也许我可以做一系列哈希或其他事情,但我对 Perl 比较陌生,甚至不知道如何解决这个问题......任何建议都将不胜感激!

谢谢

【问题讨论】:

    标签: perl


    【解决方案1】:

    如果我们谈论的是一小组值,你可以有一个数组散列:

    %lookups = ( pet => [ "dog", "cat", "fish" ],
                 color => [ "red", "blue", "purple", "brown", "white" ] );
    

    然后,当您阅读文件时,请对照哈希检查每个关键字。如果它有一个包含该关键字的键,请将您读取的行中的值替换为哈希中的值。

    【讨论】:

    • 嗯,我没想过要对数组进行哈希处理。我去看看谢谢
    【解决方案2】:

    用法: script.pl file.txt > output.txt

    use strict;
    use warnings;
    
    my %tags = (
        "pet" => [ qw(dog cat fish) ],
        "color" => [ qw(red blue purple brown white) ],
    );
    
    my $rx = join '|', keys %tags;
    
    while (<>) {
        s/^\s*($rx):\s*(\d+)/$1: $tags{$1}[$2]/;
        print;
    }
    

    【讨论】:

    • 我有一个后续问题。如果我想做诸如将所有分号更改为等号之类的事情怎么办。我必须通过文件两次还是可以在 while()
    • s/;/=/g。您可能想在文档中了解这些内容:link
    【解决方案3】:

    应该这样做

    use strict;
    
    my $inputFileName = 'E:\test.txt';
    my $outputFileName = 'E:\test2.txt';
    
    
    my %Colors = ( 1 => 'Red' , 2 => 'Green' , 4 => 'Blue' );
    my %Pets = ( 1 => 'Dog' , 2 => 'Cat' );
    
    open( IN , "<" , $inputFileName) or die "$inputFileName could not be opened $!";
    open( OUT, ">" , $outputFileName) or die "$outputFileName could not be opened $!";
    
    while(<IN>)
    {
        my $line = $_;
        if (/^(\s*pet\s*:\s*)(\d+)/ )
        {
            $line = $1. $Pets{$2} . "\n";
        }
        elsif (/\s*^color\s*:\s*(\d+)/ )
        {
           $line = $1. $Colors{$2} . "\n";
        }
    
        print OUT $line;
    }
    close(IN);
    close(OUT);
    

    【讨论】:

    • 如果我想从命令行读取文件,我可以更改“my $inputFileName = $ARGV[1]”对吗?
    • $ARGV[1] 是第二个参数,$ARGV[0] 是第一个参数。但为什么要把事情复杂化?如果您使用命令行文件名,只需使用while (&lt;&gt;),它将自动为您打开文件。
    【解决方案4】:

    使用zigdon的建议

    #!/usr/bin/perl
    use strict;
    use warnings;
    use 5.014;
    
    my %param = (pet   => [qw/dog cat fish/],
                 color => [qw/ red blue purple brown white/],
    );
    
    while (<DATA>) {
        if (/^(pet|color):\s*(\d)$/) {
            print "$1: $param{ $1 }[$2]\n";
        }
        else {
            print;  
        }
    }
    
    
    __DATA__
    id: 1
    Relationship: ""
    name: shelby
    pet: 1
    color:4
    

    【讨论】:

      【解决方案5】:

      如果情况不多,你可以试试这样,用perl -p运行:

      if (/^id/) 
      {
          s/\d+/%h=(1=>"dog",2=>"warf",3=>"ee");$h{$&}/e;
      }
      if (/^other/) 
      { 
          s/\d+/%h=(1=>"other_thing",3=>"etc",4=>"etc2");$h{$&}/e;
      }
      

      编辑:

      要自动化测试,您可以执行以下操作(也借鉴 zigdon 的哈希概念):

      my @interesting_tags = ("color", "pet");
      my $regexp = "(" .  join("|" , @interesting_tags) . ")";
      
      my %lookups = ( pet => [ "dog", "cat", "fish" ],
                      color => [ "red", "blue", "purple", "brown", "white" ] );
      
      
      while (<>)
      {
          if (/$regexp/)
          {
              my $element = $&;
              s/\d+/$lookups{$element}[$&]/e;
          }
      }
      

      【讨论】:

      • 不幸的是,我要查找大约 20 件事情,但每件事情只有大约 4 个相关联的数字。但是如果我找不到更优雅的解决方案,拥有一堆 IF 语句将起作用
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-05-09
      • 1970-01-01
      • 2016-04-27
      • 2011-04-09
      • 2018-07-25
      • 2013-11-29
      • 2013-03-23
      相关资源
      最近更新 更多