检查文本行中的字段是否与值匹配

时间:2017-11-24 11:00:47

标签: perl

我一直在使用以下Perl代码从多个文本文件中提取文本。它工作正常。

其中一个输入文件中的几行示例:

Fa0/19    CUTExyz     notconnect   129         half    100 10/100BaseTX
Fa0/22    xyz MLS     notconnect   1293        half     10 10/100BaseTX

我需要的是精确匹配每一行中的数字(即1291293不匹配)并打印相应的行。

将一系列数字与特定数字相匹配也很好,即匹配2到10但不是11到12到20

#!/perl/bin/perl

use warnings;

my @files = <c:/perl64/files/*>;

foreach $file ( @files ) {

    open( FILE, "$file" );

    while ( $line = <FILE> ) {
        print "$file $line" if $line =~ /123/n;
    }

    close FILE;
}

感谢您提出建议,但可以使用上面的代码结构吗?

3 个答案:

答案 0 :(得分:3)

我建议你看看perldoc perlre

你需要锚定你的正则表达式模式。最简单的方法可能是使用\b,它是字母数字和非字母数字之间的零宽度边界。

#!/perl/bin/perl
use warnings;
use strict;

foreach my $file ( glob "c:/perl64/files/*" ) {
   open( my $input, '<', $file ) or die $!;
   while (<$input>) {
      print "$file $_" if m/\b123\b/;
   }
   close $input;
}

注意 - 你应该使用三个参数open和上面的词法文件句柄,因为这是更好的做法。

我还删除了n模式修饰符,因为它看似多余。

编辑后,给我们一些源数据。我建议解决方案是使用正则表达式 - 您的源数据看起来是空格分隔的。 (也许那些是标签?)。

所以我建议你最好使用split并选择你想要的字段,然后用数字进行测试,因为你提到了匹配的范围。这不适合正则表达式,因为它们不理解数字内容。

相反:

while ( <$input> ) {
   print if (split)[-4] == 129;
}

注意 - 我在-4中使用split,该列表来自列表的 end 。 这是因为第3列包含空格,因此除非我们从数组末尾倒数,否则在空格上拆分会产生错误的结果。使用负索引,我们每次都得到正确的字段。

如果您的数据以制表符分隔,则可以使用chompsplit /\t/。或者可能在/\s{2,}/上拆分以拆分2或更多空格

但是通过选择字段,您可以对其进行数字测试,例如

if $fields[-4] > 100 and $fields[-4] < 200

答案 1 :(得分:2)

我希望你没有得到你要求的答案,因为你不熟悉Perl而放弃了最佳实践。询问如何编写丑陋的解决方案是不合适的,因为适当的Perl 超出了您的范围

正如在本网站上反复说过的那样,如果你不知道如何做某份工作,那么你应该聘请知道并付钱给他们工作的人。我所知道的其他职业都没有期望免费完成高质量的工作

以下是您的代码的一些注意事项。无论你在哪里学习过技巧,你都在寻找一个非常过时的资源

  • 确实有一个根目录perl,那么你的编译器是/perl/bin/perl吗?这非常不寻常,并且不需要在Windows中使用 shebang

  • 使用use strict的变量尽可能接近其第一个使用点。出于某种原因,您使用use warnings 'all'但不使用my

  • 执行此操作
  • 最好将@files替换为$file。否则代码不太清楚,因为Perl会重载<c:/perl64/files/*>运算符

  • 不要将变量名放在双引号内。它最多是不必要的,并可能导致错误。因此glob 'C:/perl64/files/*'应为<>

  • 始终使用"$file"的三参数版本,以便第二个参数为开放模式

  • 不要使用全局文件句柄。并且始终测试文件是否已正确打开,如果$file失败,则会显示包含open - 原因的消息而导致失败的消息

    $!

    应该是

    open
  • 不要依赖正则表达式模式。在这种情况下,如果您的记录具有固定宽度字段,则open( FILE, "$file" ) 似乎是更好的选项,或者open my $fh, '<', $file or die qq{Unable to open "$file" for input: $!} 。在我的解决方案中,我使用了split&#34;多个空格&#34;,但如果您的真实数据与您显示的不同(制表符分隔?),那么这不会起作用

    请注意,unpack也会与您当前的方法相匹配

此Perl程序过滤您的数据,打印第四个字段split(由多个空白字符描绘)在数字上等于Fa0/129

的行

当输入为单个文件$lines[3]时,会显示所显示的输出,其中包含问题中显示的数据

129

输出

splitn.txt

答案 2 :(得分:1)

你的问题不清楚。当你说:

  

我需要的是准确匹配每行中的数字

这可能意味着一些事情。这可能意味着每行只包含您想要匹配的单个数字。在这种情况下,使用==可能比使用正则表达式更好。或者它可能意味着你在一行上有很多文字而你只想匹配完整的数字。在这种情况下,您应该使用\b(&#34;字边界&#34;锚点) - /\b123\b/

如果您在问题中更清楚(可能是通过提供样本输入),那么人们就不必猜测您的意思。

您的代码还有几点:

  • 始终包括use strictuse warnings
  • 始终检查open()的返回值,并对失败采取适当的措施。
  • 使用词法文件句柄和open()的3-arg版本。
  • 无需在$file来电中引用open()
  • 使用$_可以简化您的代码。
  • 除非你的正则表达式包含括号,否则匹配运算符上的
  • /n无效。

将所有内容放在一起(假设我对您的问题的第二种解释是正确的),您的代码可能如下所示:

#!/perl/bin/perl

use strict;
use warnings;

my @files = <c:/perl64/files/*>;

foreach my $file (@files) {
  open my $file_h, '<', $file
    or die "Can't open $file: $!";

  while (<$file_h>) {
    print "$file $_\n" if /\b123\b/;
  }

  # No need to close $file_h as it is closed
  # automatically when the variable goes out
  # of scope.
}