将字符串替换为另一个字符串

时间:2014-09-18 13:35:20

标签: perl cygwin

在这个例子中,我想原地修改文件(没有饼图):

# Initialise file
open my $fh, '>', 'test';
print $fh 'I love apples';
close $fh;

# Do the replacement
open $fh, '+<', 'test';
s/love/hate/ while(<$fh>);
close $fh;

# Test content (should be 'I hate apples')
open $fh, '<', 'test';
print while(<$fh>);
close $fh;

不幸的是这个例子不起作用。我只找到了这个丑陋的解决方案:

# Do the replacement
open $fh, '<', 'test';
my $out;
my $changes;
while(<$fh>) {
    $changes += $_ =~ s/love/hate/;
    $out.=$_;
}
if($changes) {
    open $fh, '>', 'test';
    print $fh $out;
}
close $fh;

有更好的解决方案吗?

要求:如果有什么要改变,我只想触摸我的文件。 提示:我在Windows / Cygwin上:(

2 个答案:

答案 0 :(得分:2)

除非替换长度相同;你必须从替换点向前重写文件,以插入/删除其中的一个字母。

-i选项通常使用临时文件实现。所有更改都将写入临时文件,该文件最后重命名为原始文件名:

$ perl -i -pe's/a/bc/g' input1
$ <input2 perl -pe's/a/bc/g' >output && replace output input2
$ <input3 perl -pe's/a/bc/g' | sponge input3

即,

while(<$fhorig>) {
  $changed += $_ =~ s/love/haaate/;
  print $fhtmp $_;
}
# close, fsync files..
rename $tmp, $orig if $changed;

如果输入文件很小;你可以在没有临时文件的情况下在内存中进行更改。你在问题中的代码就是这样做的。

如果替换长度相同,那么您可以mmap该文件并在其中进行更改。 Windows和Unix都支持mmap。它允许使用大文件,就好像它是一个字符串,或者你可以使用read / seek / write来模拟它。

答案 1 :(得分:2)

相关文件:

在您的情况下,我建议使用$INPLACE_EDIT作为上述两个常见问题条目之一的模型。

use strict;
use warnings;
use autodie;

my $file = 'test';

# Initialise file
open my $fh, '>', $file;
print $fh <DATA>;
close $fh;

# Do the replacement
local @ARGV = $file;
local $^I   = '.bak';
while (<>) {
    s/love/hate/;
    print;
}
unlink "$file$^I";    # Optionally delete backup

# Test content (should be 'I hate apples')
open $fh, '<', 'test';
print <$fh>;
close $fh;

__DATA__
I love apples
I love oranges
I love bananas

输出:

I hate apples
I hate oranges
I hate bananas

注意:如果您使用的是Windows,那么您需要为-i指定备用扩展程序。因此,我总是这样做是跨平台兼容的。