繁体   English   中英

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

[英]How to select specific columns from a .txt file using perl

我最近听说过有关awkperl并且我相信它们是处理原始数据文件的绝佳工具,因此我想熟悉Perl

我想到要播放.txt文件 在此文件中,首先有一些字符串。 我想做的是在单独的.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

输出应包含六列中的数据,但不包含其单位。

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行获取数据,并将第output.txt和9列打印到output.txt文件中。


更新资料

我还看到您正在使用行号。 如果出现一个格式相同但数据数量不同的新文件,是否有另一种方法可以执行相同的操作而不必计算行数?

您可以从第一个-----------一直到-----------------------------------------------------------

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

该代码段可以完成您想要的操作,并且您应该能够在不同长度的文件上使用它,只要您想要的数字在--------

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到一个count变量。

s/[a-zA-Z]//g将删除所有字母。

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

这可能不是解决问题的最优雅的方法,但是它应该可以正常工作并且很容易让您动起来。

从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
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; 

由于这是一个小型文本文件,因此一种选择是将文件的内容读取为字符串,使用正则表达式捕获表,然后使用另一个正则表达式捕获cols 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]

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

第一行将文件内容插入$content 第二行的正则表达式捕获-----\\n\\n----- (表)之间的所有文本,并将捕获的表放入$table 最后,最后一个正则表达式全局“查找”列val(请注意,正则表达式使用列的单位来查找它们),并while找到它们while将它们print

希望这可以帮助!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM