Perl:如何在文件中使用正则表达式进行替换?

时间:2016-03-23 13:46:48

标签: regex perl

我正在编写一个脚本,它将读取包含Angstroms测量结果的文件,并将它们转换为nm(1埃= 0.1 nm)。

以下是一些示例,它应该找到并替换:

3A

12 A

2.75 angstroms

0.123 Angstroms

不应改变以下示例: 我喜欢数字3.一个非常好的数字。伦敦动物园里有27个Aardvarks。

这是我到目前为止所得到的。有两件事我有问题,我怎么能表现出来"以10"找到匹配后将其写回文件?我只是不知道正则表达式应该如何看待这个问题。

use strict;
use warnings;

my $filename = 'angstrom.txt';   

open(FILE, $filename) or die "Can't open $filename: $!";
my @lines = <FILE>;
close(FILE);

open(FILE, ">$filename") or die "Can't write to $filename: $!";
foreach my $line (@lines) {
    if($line =~ s/\d{2}\w//e)
    {   
        print FILE (@lines); 
    }
}
close(FILE);

1 个答案:

答案 0 :(得分:1)

正则表达式的问题在于 - 他们并不擅长理解&#39;一个数值。他们关于文字。

你可以在这种特定情况下做到这一点,因为你要除以10,但我通常不称它为好主意。

相反 - 提取要更改的值,并对其应用乘法:

s|([\d\.]+) angstroms|$1 / 10 . " nm"|eig;

这将捕获&#39;数字+小数&#39;在“埃”之前,除以10,然后加入“&#39; nm&#39;代替。

  • i标志使匹配大小写不敏感。
  • e标记表示评估&#39;替换为perl。
  • g要做到这一点&#34;全球&#34;每行 - 根据您的示例数据,这可能无关紧要。

注意 - 我们还使用|而不是更常见的/分隔符,因为我们在表达式中使用/。 (你可以逃脱它,但我认为这更清楚了)

为了对您的文件执行此操作,我们可以使用perlrun标记-i - 就地编辑。 (在指定扩展名之后 - 它将源重命名为该扩展名,然后重新编写该文件)

perl -i.bak -pe 's|([\d\.]+) angstroms|$1 / 10 . " nm"|eig' angstrom.txt

或者您可以将上述内容拼接到您的代码中。

我通常会建议避免读写&#39;这样的操作,因为它确实意味着代码故障意味着您丢失了源数据。打开一个新的输出文件,然后写入它 - 然后在完成(成功)后重命名它是一种更好的做法。

(它还消耗与源文件成比例的内存。这通常不是问题,但有时可能变得相关)。

鉴于您的代码需要匹配A,Angstrom或Angstroms(我假设您没有&#39; amps&#39;担心?)

perl -i.bak -pe 's|([\d\.]+)\s*a(?:ngstroms)?\b|$1 / 10 . " nm"|ei'  angstrom.txt

这是匹配aAangstromsAnstroms的额外步骤,我们\b要求立即断言。所以&#34; 12苹果&#34;不会抓住我们。

也许具有讽刺意味的是 - -i.bak -pe实际上可能比写出它更容易。但是如果你想要:

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

my $filename = 'angstrom.txt';   

open(my $input, '<', $filename) or die "Can't open $filename: $!";
open(my $output, '>', $filename.".new" ) or die $!; 

select $output; 
while ( <$input> ) {
    s|([\d\.]+)\s*a(?:ngstroms)?\b|$1 / 10 . " nm"|eig;
    print;
}
close ( $input );
close ( $output );

#rename .new here