【问题标题】:how to match string in perl with a variable rather than regex如何将perl中的字符串与变量而不是正则表达式匹配
【发布时间】:2015-03-02 01:40:25
【问题描述】:

我有一个要使用 perl 检测的文件名数组。

我还有很多,但这个例子只是为了说明:

@toremove = (100, 102, 104, 131, 156);

现在我想打开目录并浏览文件,如果它们碰巧有上面数组中的任何文件名,我想采取一些措施。

opendir (DIR, "D:/MYPATH/");
while (my $file = readdir(DIR)) {
    if($file =~ <how do i reference an array item here?>.txt)
    { // do something }

有没有办法说文件是否恰好匹配数组中的任何项目?所以这更像是一个“变量字符串匹配”......

【问题讨论】:

    标签: arrays regex string perl string-matching


    【解决方案1】:

    我会先将数组转换为散列,然后简单地测试该键是否存在于散列中。

    my @toremove = (100, 102, 104, 131, 156);
    my %lookup_hash;
    $lookup_hash{"$_.txt"} = 1 for @toremove;
    
    opendir (my $DIR, "D:/MYPATH/");
    while (my $file = readdir($DIR)) {
        if( $lookup_hash{$file} )
        { // do something }
    

    【讨论】:

      【解决方案2】:

      每当你对自己说我怎样才能快速找到列表中的东西时,你应该对自己说Hash!

      让我们将@toremove 列表转换为哈希。我们可以使用map 命令来做到这一点。 map 命令起初有点吓人,我不相信它的联机帮助页能做到这一点。其实没那么复杂:

       @some_hash_or_array = map { .... } @original_array;
      

      map 接受@original_array 并循环遍历该数组的每个条目。 {...} 是您要在每个条目上运行的小程序。

      您可以将map 视为某事,如下所示:

      my @original_array = qw( ... );
      my @some_hash_or_array;
      for my $entry ( @original_array ) {
          push @some_hash_or_array, { ... };
      }
      

      map 之所以有用是因为数组的每个条目都设置为$_,因此操作$_ 可以让您转换数组。

      我正在做的是:

      my %files = map { $_.".txt" => 1 } @to_remove;
      

      当这个map 命令处理@to_remove 时,它会创建另一个数组,如下所示:

      ("100.txt" => 1, "102.txt" => 1, "104.txt" => 1, "131.txt" => 1, "156.txt" => 1)
      

      我用这个数组初始化我的%files 哈希。奇数条目是散列的,键后的偶数条目是数据。

      #! /usr/bin/env perl
      #
      use strict;             # Lets you know when you misspell variable names
      use warnings;           # Warns of issues (using undefined variables)
      use feature qw(say);
      
      my @to_remove = qw(100 102 104 131 156);
      
      my %files = map { $_.".txt" => 1 } @to_remove;
      while ( my $file = <DATA> ) {
          chomp $file;
          if ( exists $files{$file} ) {
              say qq(File "$file" is in the list);
          }
          else {
              say qq(File "$file" isn't in the list);
          }
      }
      
      __DATA__
      100.txt
      203.txt
      130.txt
      104.txt
      150.txt
      156.txt
      160.txt
      

      这会产生:

      File "100.txt" is in the list
      File "203.txt" isn't in the list
      File "130.txt" isn't in the list
      File "104.txt" is in the list
      File "150.txt" isn't in the list
      File "156.txt" is in the list
      File "160.txt" isn't in the list
      

      您需要这样做:

      #! /usr/bin/env perl
      #
      use strict;             # Lets you know when you misspell variable names
      use warnings;           # Warns of issues (using undefined variables
      use autodie;            # Automatically kills the program if opens fail
      use feature qw(say);
      
      my @to_remove = qw(100 102 104 131 156);
      opendir my $dir_fh, "dir_name";
      
      my %files = map { $_.".txt" => 1 } @to_remove;
      while ( my $file = < $dir_fh > ) {
          if ( exists $files{$file} ) {
              say qq(File "$file" is in the list);
          }
          else {
              say qq(File "$file" isn't in the list);
          }
      }
      

      【讨论】:

        【解决方案3】:

        我会转换数组的每个元素,然后使用智能匹配运算符:

        #!/usr/bin/perl
        use Modern::Perl;
        
        my @toremove = (100, 102, 104, 131, 156);
        my @txt = map{$_.'.txt'}@toremove;
        while(<DATA>) {
            chomp;
            if ($_ ~~ @txt) {
                say "==> $_ : found";
            } else {
                say "$_ : NOT found";
            }
        }
        
        __DATA__
        abc
        def.txt
        100
        102.txt
        131.abc
        156.txt
        

        输出:

        abc : NOT found
        def.txt : NOT found
        100 : NOT found
        ==> 102.txt : found
        131.abc : NOT found
        ==> 156.txt : found
        

        【讨论】:

        • 智能匹配运算符已标记为experimental。它们在 5.20 中再次更改,我强烈建议不要使用它,因为它在不断发展。
        【解决方案4】:

        这里有几个选择:

        ##  Shorthand hash definition
        @toremove{100, 102, 104, 131, 156}= (1) x 5;
        
        ##  Using a glob instead of opendir
        for (<D:/MYPATH/*>)
        {
            ##  Use a regex for flexibility
            if (m:.*/(.+)$: and $toremove{$1})
            {
                print "Doing something to $_\n";
            }
        }
        

        【讨论】:

        • 你要@toremove{100, 102, 104, 131, 156} = (1) x 5
        • 谢谢,布拉德。我不知道最后四个元素会被初始化为空。
        猜你喜欢
        • 2021-07-28
        • 1970-01-01
        • 1970-01-01
        • 2014-12-31
        • 2016-10-22
        • 2014-08-06
        • 1970-01-01
        • 1970-01-01
        • 2017-08-29
        相关资源
        最近更新 更多