2

在使用 perl 修复此正则表达式代码时,我需要您的专业帮助吗?

我有这个数据文件...

__数据__
SCSI - 测试-A
cccccccccccccccc
啊啊啊啊啊啊啊
bbbbbbbbbbbbbbbbb

__数据__
SCSI - 测试-B
cccccccccccccccc
啊啊啊啊啊啊啊
bbbbbbbbbbbbbbbbb

__数据__
SCSI - 测试-C
cccccccccccccccc
啊啊啊啊啊啊啊
bbbbbbbbbbbbbbbbb

我想要以下输出

__数据__
SCSI - 测试-A

__数据__
SCSI - 测试-B

__数据__
SCSI - 测试-C

相反,我得到的输出缺少__Data__两个数据记录。

__数据__
SCSI - 测试-A
SCSI - 测试-B
SCSI - 测试-C

这里的代码..

$/ = "__Data__"; # setting the input separator variable to __Data__

while(<ReadFile>)
{
   $_ =~ s/(SCSI.*test-(A|B|C)?)(.*)/$1/ms;
   print $_;
}
4

4 回答 4

2

你告诉 Perl 那行以 结尾__DATA__,所以你得到

1: "__Data__"
2: "\nSCSI - test-A\nccc\naaa\nbbb\n\n__Data__"
3: "\nSCSI - test-B\nccc\naaa\nbbb\n\n__Data__"
4: "\nSCSI - test-C\nccc\naaa\nbbb\n"

但你错误地认为你得到了

1: "__Data__\nSCSI - test-A\nccc\naaa\nbbb\n\n"
2: "__Data__\nSCSI - test-B\nccc\naaa\nbbb\n\n"
3: "__Data__\nSCSI - test-C\nccc\naaa\nbbb\n"

解决方案:

my $after_data = 0;
while (<>) {
   if (/^__Data__$/) {
      print;
      $after_data = 1;
   }
   elsif ($after_data) {
      print;
      print "\n";
      $after_data = 0;
   }
}

您还可以使用段落模式:

local $/ = '';
while (<>) {
   print /^(.*\n.*\n)/;
   print "\n";
}
于 2012-05-17T22:27:07.297 回答
0

您似乎想要打印符合三个类别之一的行。

  1. __Data__标记
  2. SCSI 测试线
  3. 空行

Perl 的段落模式在工作时很方便,但它很脆弱。段落完全由 sequence终止"\n\n",但是当段落后面有一个空白但非空的行时,不显示空格的编辑器会使调试变得棘手。

正如您在问题中所写,下面的代码会产生您想要的输出。

#! /usr/bin/env perl

use strict;
use warnings;
use 5.10.0;  # smart matching

*ARGV = *DATA;  # for demo only

my @interesting_line = (qr/^__Data__/, qr/SCSI - test-/, qr/^\s*$/);

while (<>) {
  print if $_ ~~ @interesting_line;
  print "\n" if eof && !eof();
}

__DATA__
__Data__
SCSI - test-A
ccccccccccccccccc
aaaaaaaaaaaaaaaaa
bbbbbbbbbbbbbbbbb

__Data__
SCSI - test-B
ccccccccccccccccc
aaaaaaaaaaaaaaaaa
bbbbbbbbbbbbbbbbb

__Data__
SCSI - test-C
ccccccccccccccccc
aaaaaaaaaaaaaaaaa
bbbbbbbbbbbbbbbbb

在实际使用中,您将删除标记为仅用于演示的行,然后在命令行上提供一个或多个数据文件。这个看起来很有趣的if eof && !eof()测试试图确定何时在记录之间插入额外的分隔符。如果您希望它完全正确,则需要更加深思熟虑。

下面是多个文件的输入示例。

$猫输入1
__数据__
SCSI - 测试-A
cccccccccccccccc
啊啊啊啊啊啊啊
bbbbbbbbbbbbbbbbb

__数据__
SCSI - 测试-B
cccccccccccccccc
啊啊啊啊啊啊啊
bbbbbbbbbbbbbbbbb

$猫输入2
__数据__
SCSI - 测试-C
cccccccccccccccc
啊啊啊啊啊啊啊
bbbbbbbbbbbbbbbbb

$ ./extract-tests 输入1 输入2
__数据__
SCSI - 测试-A

__数据__
SCSI - 测试-B

__数据__
SCSI - 测试-C
于 2012-05-26T15:14:24.727 回答
0

尝试添加

    $\ = $/;

…也设置你的输出记录分隔符。

但是,您最终会__Data__以这种方式得到最终的虚假实例,因为它是在每条记录之后打印的(在 each 的末尾print)。

或者,您可以自己拆分输入:

  while (<ReadFile>)
  {   chomp;
      next unless $_ eq '__Data__'; print;
      my $next = <ReadFile>;
      $next =~ s/(SCSI.*text-(A|B|C)?).*/$1/ms;
      print $next;
  }
于 2012-05-17T22:13:11.843 回答
0

将输入记录分隔符设置为空字符串以启用段落模式。在打印中添加换行符。

$/ = ""; # paragraph mode

while (<ReadFile>) {
    $_ =~ s/(SCSI.*test-(A|B|C))(.*)/$1/s;
    print "$_\n\n";
}
于 2012-05-17T22:23:20.723 回答