如何让perl在特定字符串后打印n行?

时间:2015-05-14 00:04:53

标签: regex perl grep

我有一个非常大的文件,想要拉出所有原子符号和平衡几何的坐标。所需信息显示如下:

       ***** EQUILIBRIUM GEOMETRY LOCATED *****  
COORDINATES OF ALL ATOMS ARE (ANGS)    
       ATOM CHARGE     X              Y              Z     
-----------------------------------------------------------  
C           6.0   0.8438492825  -2.0554543742   0.8601734285  
C           6.0   1.7887997955  -1.2651150894   0.4121141006  
N           7.0   1.3006136046   0.0934593194   0.2602148346

注意:坐标完成后会出现一个空行。

到目前为止,我已修补了一段对我有意义的代码,但是它会产生错误,我不确定原因。 它在调用脚本后需要一个文件,当它看到包含EQUILIBRIUM GEOMETRY的字符串触发记录符号和坐标时,保存每一行并更改为$ start == 1。它继续保存包含坐标格式的行,直到它看到一个空白行,完成记录到$ geom。

#!/usr/bin/perl

$num_args = $#ARGV + 1;
if ($num_args != 1) {
   print "\nMust supply GAMESS .log file.\n";
   exit;
}

$file = $ARGV[0];
open FILE, "<", $file;

$start = 0;
$geom="";
    
while (<FILE>) {
 $line = $_;
  if ( $line eq "\n" && ($start == 1) ) {
       $start = 0; }

 if ( $start == 1 && $line =~ m/\s+[A-Z]+\s+[0-9\.]+\s+[0-9\.\-]+\s+[0-9\.\-]+\s+[0-9\.\-]+/ ) {
$line =~ s/^\s+//;
@coordinates = split(/\s+/,$line);
$geom=$coordinates[0],$coordinates[3],$coordinates[4],$coordinates[5];

 }
 if ( $line =~ m/\s+\*+ EQUILIBRIUM GEOMETRY LOCATED\s\*+\s+) {
   $geom = "";
   $start = 1;
 }
}

print $geom; 

错误讯息: Unrecognized character \xC2; marked by <-- HERE after <-- HERE near column 1 at ./perl-grep line 5.

3 个答案:

答案 0 :(得分:1)

第13行有一个不可见的字符

我创建了一个只包含此行的文件(通过剪切/粘贴) 然后在上面添加一行是我的重新输入

$的geom =&#34;&#34 ;;

$的geom =&#34;&#34 ;;

看起来相同但不是(第二行是有缺陷的)

[tmp]=> cat x | perl -ne '$LINE = $_; $HEX = unpack "H*"; print "$HEX $LINE" '
2467656f6d3d22223b0a $geom="";
2467656f6d3d22223be280a80a $geom="";

当您对文件进行六分法时,可以看到还有一些字符。 所以=&gt;只需完全删除这一行并重新输入

顺便提一下,您的文件中还有另一个问题,您错过了关闭正则表达式&#39; /&#39;

if ( $line =~ m/\s+\*+ EQUILIBRIUM GEOMETRY LOCATED\s\*+\s+) {

但我想,完成你的剧本还有很多工作要做,因为我没有看到太多的目的;)

答案 1 :(得分:0)

我把它复制到我的Linux盒子里并遇到了同样的问题。

基本上,该剧本说该行中有一个不可读的角色:

$geom="";

我在gedit中重新键入了该行并运行了文件。

此外,脚本底部还有一个未封闭的正则表达式。我添加一个&#34; /&#34;到以下行:

if ( $line =~ m/\s+\*+ EQUILIBRIUM GEOMETRY LOCATED\s\*+\s+) {

答案 2 :(得分:0)

好的,首先 - strictwarnings真的是当你写一个scirpt并遇到问题时的第一个停靠点。实际上,即使在你遇到问题之前 - 打开它们并坚持它们。*

与你的代码一样:

  • $geom="";? - 尾随问号。应该删除。
  • $num_args = $#ARGV + 1; - 多余的。 scalar @ARGV具有相同的结果。
  • open FILE, "<", $file; - 3 arg open是好的。不使用词法文件句柄或检查成功是不好的。
  • $line = $_; - 多余的。只需使用while ( my $line = <FH> ) {代替。
  • if ( $line =~ m/\s+\*+ EQUILIBRIUM GEOMETRY LOCATED\s\*+\s+) - 破坏的正则表达式,没有尾随/
  • $geom=$coordinates[0],$coordinates[3],$coordinates[4],$coordinates[5]; - 没有做你的想法。您可能希望join这些或连接它们。
  • $line eq "\n" - 选择空行,但如果您chomp;优先eq '',可能会更好。
  • $start看起来您正在尝试与range运营商做同样的事情。 http://perldoc.perl.org/perlop.html#Range-Operators
  • 你随时覆盖$geom。这是你的意图吗?
  • $line =~ s/^\s+//; - 如果您所做的只是split,则是多余的。 split ' '做同样的事情。
  • 使用它后,close文件句柄的良好形式。特别是当它没有词汇范围时。

因此,考虑到这一点,您的代码可能看起来像这样:

#!/usr/bin/perl

use strict;
use warnings;

if ( @ARGV != 1 and not -f $ARGV[0] ) {
    print "\nMust supply GAMESS .log file.\n";
    exit;
}

open( my $input_fh, "<", $ARGV[0] ) or die $!;

my $geom = "";
while ( my $line = <$input_fh> ) {
    chomp $line;
    if ( $line =~ m/\s+\*+ EQUILIBRIUM GEOMETRY LOCATED\s\*+\s+/ .. m/^$/ ) {
        if ( $line
            =~ m/\s+[A-Z]+\s+[0-9\.]+\s+[0-9\.\-]+\s+[0-9\.\-]+\s+[0-9\.\-]+/
            )
        {
            my @coordinates = split( ' ', $line );
            $geom = join( "",
                $coordinates[0], $coordinates[3],
                $coordinates[4], $coordinates[5] );

        }
    }
}
close($input_fh);
print $geom;

(如果你有一些样本输入,我会验证它)。

*有时您可能想要关闭它们。如果您知道这些是什么以及为什么,那么您将其关闭。否则只是假设他们是强制性的。