如何使用perl从.txt文件中选择特定列

时间:2013-12-09 11:29:41

标签: windows perl awk

我最近听说过awkperl,我相信这些是处理原始数据文件的绝佳工具,所以我想熟悉Perl

我想过玩.txt file。在这个文件中,首先有一些字符串。我想要做的是打印一个单独的.txt文件,一些列(即第一个和第四个)没有他们的单位。

我看到我必须以某种方式使用连字符(-)之间的线条,这就是算法。

问题是我不知道如何在perl中执行此操作。任何想法或帮助都非常受欢迎!!!

该文件的格式为

 ==================================================================
              Calculation using SRIM-2006
              SRIM version ---> SRIM-2008.04
              Calc. date   ---> December 05, 2013
 ==================================================================

 Disk File Name = SRIM Outputs\Helium in Silicon

 Ion = Helium [2] , Mass = 4.003 amu

 Target Density =  2.3212E+00 g/cm3 = 4.9770E+22 atoms/cm3
 ======= Target  Composition ========
    Atom   Atom   Atomic    Mass    
    Name   Numb   Percent   Percent  
    ----   ----   -------   -------  
     Si     14    100.00    100.00  
 ====================================
 Bragg Correction = 0.00%
 Stopping Units =  MeV / (mg/cm2)
 See bottom of Table for other Stopping units

   Ion        dE/dx      dE/dx     Projected  Longitudinal   Lateral
  Energy      Elec.      Nuclear     Range     Straggling   Straggling
-----------  ---------- ---------- ----------  ----------  ----------
 500.00 keV   1.452E+00  3.238E-03    1.98 um     1891 A      2389 A  
 550.00 keV   1.449E+00  2.999E-03    2.13 um     1921 A      2443 A  
 600.00 keV   1.441E+00  2.795E-03    2.27 um     1951 A      2495 A  
 650.00 keV   1.430E+00  2.619E-03    2.42 um     1979 A      2545 A  
 700.00 keV   1.416E+00  2.466E-03    2.57 um     2007 A      2594 A  
 800.00 keV   1.384E+00  2.211E-03    2.88 um     2084 A      2689 A  
 900.00 keV   1.349E+00  2.007E-03    3.19 um     2160 A      2782 A  
   1.00 MeV   1.312E+00  1.839E-03    3.51 um     2237 A      2874 A  
   1.10 MeV   1.276E+00  1.700E-03    3.84 um     2314 A      2967 A  
   1.20 MeV   1.240E+00  1.581E-03    4.18 um     2392 A      3060 A  
   1.30 MeV   1.206E+00  1.479E-03    4.53 um     2471 A      3153 A  
   1.40 MeV   1.172E+00  1.390E-03    4.89 um     2551 A      3249 A  
   1.50 MeV   1.141E+00  1.312E-03    5.26 um     2633 A      3345 A  
   1.60 MeV   1.111E+00  1.243E-03    5.65 um     2716 A      3444 A  
   1.70 MeV   1.082E+00  1.181E-03    6.04 um     2801 A      3544 A  
   1.80 MeV   1.055E+00  1.126E-03    6.44 um     2888 A      3647 A  
   2.00 MeV   1.005E+00  1.030E-03    7.27 um     3176 A      3858 A  
   2.25 MeV   9.495E-01  9.320E-04    8.37 um     3605 A      4135 A  
   2.50 MeV   9.002E-01  8.522E-04    9.53 um     4031 A      4426 A  
   2.75 MeV   8.564E-01  7.857E-04   10.75 um     4456 A      4732 A  
   3.00 MeV   8.172E-01  7.294E-04   12.04 um     4883 A      5053 A  
   3.25 MeV   7.821E-01  6.811E-04   13.38 um     5312 A      5388 A  
   3.50 MeV   7.503E-01  6.391E-04   14.78 um     5744 A      5737 A  
   3.75 MeV   7.214E-01  6.024E-04   16.24 um     6180 A      6101 A  
   4.00 MeV   6.950E-01  5.698E-04   17.76 um     6619 A      6478 A  
   4.50 MeV   6.486E-01  5.148E-04   20.96 um     8162 A      7272 A  
   5.00 MeV   6.090E-01  4.700E-04   24.38 um     9630 A      8118 A  
-----------------------------------------------------------
 Multiply Stopping by        for Stopping Units
 -------------------        ------------------
  2.3211E+01                 eV / Angstrom
  2.3211E+02                keV / micron  
  2.3211E+02                MeV / mm      
  1.0000E+00                keV / (ug/cm2)
  1.0000E+00                MeV / (mg/cm2)
  1.0000E+03                keV / (mg/cm2)
  4.6637E+01                 eV / (1E15 atoms/cm2)
  4.2914E+00                L.S.S. reduced units
 ==================================================================
 (C) 1984,1989,1992,1998,2008 by J.P. Biersack and J.F. Ziegler

输出应包含六列中没有单位的数据。

5 个答案:

答案 0 :(得分:2)

使用awk

$ awk 'NR>=25 && NR<=51 {print $1, $3, $4, $5, $7, $9 > "output.txt"}' file

$ cat output.txt
500.00 1.452E+00 3.238E-03 1.98 1891 2389
550.00 1.449E+00 2.999E-03 2.13 1921 2443
600.00 1.441E+00 2.795E-03 2.27 1951 2495
650.00 1.430E+00 2.619E-03 2.42 1979 2545
700.00 1.416E+00 2.466E-03 2.57 2007 2594
800.00 1.384E+00 2.211E-03 2.88 2084 2689
900.00 1.349E+00 2.007E-03 3.19 2160 2782
1.00 1.312E+00 1.839E-03 3.51 2237 2874
1.10 1.276E+00 1.700E-03 3.84 2314 2967
1.20 1.240E+00 1.581E-03 4.18 2392 3060
1.30 1.206E+00 1.479E-03 4.53 2471 3153
1.40 1.172E+00 1.390E-03 4.89 2551 3249
1.50 1.141E+00 1.312E-03 5.26 2633 3345
1.60 1.111E+00 1.243E-03 5.65 2716 3444
1.70 1.082E+00 1.181E-03 6.04 2801 3544
1.80 1.055E+00 1.126E-03 6.44 2888 3647
2.00 1.005E+00 1.030E-03 7.27 3176 3858
2.25 9.495E-01 9.320E-04 8.37 3605 4135
2.50 9.002E-01 8.522E-04 9.53 4031 4426
2.75 8.564E-01 7.857E-04 10.75 4456 4732
3.00 8.172E-01 7.294E-04 12.04 4883 5053
3.25 7.821E-01 6.811E-04 13.38 5312 5388
3.50 7.503E-01 6.391E-04 14.78 5744 5737
3.75 7.214E-01 6.024E-04 16.24 6180 6101
4.00 6.950E-01 5.698E-04 17.76 6619 6478
4.50 6.486E-01 5.148E-04 20.96 8162 7272
5.00 6.090E-01 4.700E-04 24.38 9630 8118

它从第25行到第51行获取数据,并将第1,第3,第4,第5,第7和第9列打印到output.txt文件中。


更新

  

我也看到你正在使用行号。如果是新文件,   具有相同的格式,但具有不同数量的数据,是   有另一种方法可以做同样的事情,而不必计算线数?

您可以从第一个-----------开始查看-----------------------------------------------------------

awk '$1~/-----------------------------------------------------------/ {f=0; exit}
     $1~/-----------/ {f=1; next}
     f{print $1, $3, $4, $5, $7, $9 > "output.txt"}' file

答案 1 :(得分:1)

此代码段应该可以执行您想要的操作,并且您应该可以在不同长度的文件上使用它,只要您想要的数字介于--------之间:

my $infile = 'in.txt';
open my $input, '<', $infile or die "Can't open to $infile: $!";

my $count = 0;
while (<$input>){
    chomp;
    $count++ if /^-----/;
    s/[a-zA-Z]//g;
    print "$_\n" if $count == 1 and ! /^-----/;
    next;
}

简而言之,这将逐行读取您的文件。每次看到与正则表达式/^-----/匹配的行时,它都会+1到计数变量。

s/[a-zA-Z]//g会删除这些行中的任何字母。

如果count变量等于1且行与/^-----/不匹配,它将打印出整行。因此,它不会在/^-----/之前(作为count == 0)或在第二/^-----/之后打印出行(现在计数== 2)。

它可能不是最优雅的方式,但它应该起作用并且很容易让你自己动手。

答案 2 :(得分:1)

从Windows命令行:

perl -F'-\s+-' -ane "print if (@F == 6 ... /--/) and !/--/ and s/ [a-z]+//gi" file

来自perldoc

  

如果您不希望它在下一次评估之前测试正确的操作数,就像在sed中一样,只需使用三个点(“...”)而不是两个点。在所有其他方面,“......”的行为就像“......”一样。

更新:

perl -lane "print qq{@F[0,2,3,4,6,8]} if (/^-/ ... /^-/) and !/^-/" file

答案 3 :(得分:1)

use strict; 
use warnings;

open my $f, "<", 'input' or die("$!");

# find the data (read as long as no dashes)
while (<$f> !~ /^-----/) {}

# process the data (until there are dashes)
while (<$f>) {
    last if /^------/;  # ends with dashes
    my @v = split;
    print join(" ", @v[0,4]), "\n";
}

close $f; 

答案 4 :(得分:1)

由于这是一个小文本文件,一个选项是将文件的内容读入字符串,使用正则表达式捕获表,然后使用另一个正则表达式来捕获第1列和第4列的值:

use strict;
use warnings;

my $content = do { local $/; <> };
my ($table) = $content =~ /-----\n(.+?)\n-----/s;

while ( $table =~ /(\S+)\s+([kM]eV).+?(\S+)\s+um/g ) {
    print $2 eq 'keV' ? $1 * 1000 : $1;
    print "\t$3\n";
}

部分输出:

500000  1.98
550000  2.13
600000  2.27
650000  2.42
700000  2.57
800000  2.88
900000  3.19
1.00    3.51
1.10    3.84
1.20    4.18
1.30    4.53
1.40    4.89
1.50    5.26
...

命令行用法:>perl script.pl inFile [>outFile]

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

第一行将文件的内容篡改为<{1}}。第二行的正则表达式捕获$content-----\n(表格)之间的所有文本,捕获的表格放入\n-----。最后,全局的最后一个正则表达式“查找”列值(请注意正则表达式使用列的单位来查找它们),并且$table找到它们,它们是while。< / p>

希望这有帮助!