【问题标题】:How to match particular pattern with if condition如何将特定模式与 if 条件匹配
【发布时间】:2013-04-25 10:18:31
【问题描述】:

我的文本文件:

Name: mak
Place: ynr
Age: 22
------------- 
Name: john
Place: kkr
Age: 21
------------- 
Name: mak
Place: knl
Age: 23
-------------

我正在做的是:

open(FILE, "path to file") or die "";
$check="mak";
@arr=<FILE>
for(@arr)
{
    if ($_=/Name:\s(.*)/)
    {
        $a=$1;
        if($a eq $check)
        {
            print "matched name"
        }
        #now i want if "mak" is matched then after that it should match the age and store it one variable and then compare it with other matched age with same name
    }
}

我想先得到名字,如果匹配为“mak”,那么我还需要检查年龄并比较年龄。

【问题讨论】:

  • 那么,到目前为止,您尝试了什么?互联网上有数百个 perl 中“匹配事物”的示例。到目前为止你的代码是什么?你到底卡在哪里了?
  • edit您的问题添加您的代码/完善您的问题。不要不要在 cmets 中发布。
  • 源文件类似于YAML。有一个module 可以为您进行解析。 (但是,在 YAML 中,水平条必须是三个减号 --- 长)
  • 在你的代码中你使用 = 而不是 =~
  • 你可以使用if (/Name:\s(.*)/)匹配$_

标签: perl pattern-matching


【解决方案1】:

有很多方法可以解决这个问题,但我喜欢一种简洁的方法:

use File::Slurp;
@records=split('---',read_file('file.txt'))

现在$records[0],例如,包含:

Name: mak
Place: ynr
Age: 22

@records 中会有“垃圾”条目,因为拆分模式并不完美,但这并不重要。现在您可以遍历@records 来找到您需要的那个。

【讨论】:

  • 您好,我收到此错误:Can't locate File/Slurp.pm in @INC
  • @Mak_Thareja 您可以将read_file 替换为do{open my $fh, "&lt;", "file.txt" or die "Can't open file.txt: $!"; local $/; &lt;$fh&gt;},或者您可以从CPAN 安装File::Slurp 模块。在命令行上运行cpan File::Slurp,具体取决于您的操作系统和您安装的 perl 类型
  • 与其迭代@records“找到你需要的那个”,为什么不自己迭代原始行(并且其中不会有任何“垃圾”条目)?跨度>
  • @kenosis 我将以问题的形式回答你的问题:为什么不更进一步,遍历文件中的所有字母
  • @mak File::Slurp 是您可以从 CPAN 获得的标准包,即 cpan File::Slurp 应该可以解决问题
【解决方案2】:

您的文件格式可以描述如下:

  • 多条记录由水平条相互分隔
  • 每条记录都有多个名称-值对,每对单独一行

输入记录分隔符$/可以设置为任意字符串,所以我们可以这样做

local $/ = "-------------\n";

现在,每个 readline 操作将返回一条记录。 chomp 将删除分隔符。

从记录中获取字段很简单

my %fields = map split(/:\s*/, $_, 2), split /\n/, $record;

我们可以结合它来一次检查一条记录:

use strict; use warnings;

my $check = shift @ARGV;

local $/ = "-------------\n";
while (<>) {
  chomp;
  my %fields = map split(/:\s*/, $_, 2), split /\n/, $_;
  if ($fields{Name} eq $check) {
    # do something
  }
}

这将在命令行上调用,例如perl the-script.pl mak file.txt

【讨论】:

    【解决方案3】:

    这是另一个选择:

    use strict;
    use warnings;
    
    my @rec;
    while (<>) {
        push @rec, $1 if /^(?:Name|Place|Age):\s+(.+)/;
        next unless @rec == 3;
    
        print "@rec\n" if $rec[0] eq 'mak' and $rec[2] == 23;
    
        undef @rec;
    }
    

    用法:perl script.pl inFile [&gt;outFile]

    最后一个可选参数将输出重定向到文件。

    数据集上的输出:

    mak knl 23
    

    读取文件行时,正则表达式会查找以 Name、Age 或 Place 开头的行,然后捕获冒号后面的所有空格。 $1 中捕获的值是pushed 到@rec,并读取下一行unless 三个记录行已被处理。如果@rec 的元素零等于“mak”并且元素二等于23,则打印记录的值。最后,@recundefined,所以它已准备好进行下一条记录。

    希望这会有所帮助!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-06-15
      • 2018-12-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多