我不确定如何从 Perl 中搜索和替换单词。
我有.txt
包含随机顺序图像文件名的文件。
Animals.txt
There is an image Dog_Image_85.jpg
Cat has an image Cat_Image_front.jpg
Here is another image Dog_Image_61.jpg
Cat has another image Cat_Image_back.jpg
Next image Dog_Image_55.jpg
Next Image Cat_Image_side.jpg
Next Image Dog_Image_200.jpg
我只想将狗图像名称更改为计数器,因此:
There is an image Dog_Image_1.jpg
Cat has an image Cat_Image_front.jpg
Here is another image Dog_Image_2.jpg
Cat has another image Cat_Image_back.jpg
Next image Dog_Image_3.jpg
Next Image Cat_Image_side.jpg
Next Image Dog_Image_4.jpg
我尝试过这些但每次都出现错误:
#!/usr/local/bin/perl -w -I ../lib -I ./
use strict;
my $Animals = "Animals";
my $file = "$Animals.txt";
perl -pi -e 's/Dog_Image_.*.jpg/"Dog_Image_.++$i.jpg"/ge' $file;
这给了我一个错误:Can't use bareword perl
。
我也尝试过:
system('s/Dog_Image_.*.jpg/"Dog_Image_.++$i.jpg"/ge' $file);'
但仍然会出现错误。
5
最佳答案
3
看起来您正试图运行一个 shell 命令,该命令将调用perl
来运行 Perl 命令行程序(“单行程序”),该程序来自 Perl 脚本。这当然是可能的,但它是一种复杂的、通常被称为“饥饿”的杂技。为什么不在那个 Perl 脚本中完成这项工作呢?
这是一种方法,使用有用的库
use warnings;
use strict;
use feature 'say';
use Path::Tiny;
my $file_name = ...
...
{
my $dog_cnt = 0;
path($file_name) -> edit( sub {
s/Dog_Image_\K([0-9]+)\.jpg/++$dog_cnt . '.jpg'/ge
});
}
该方法edit
对被提取到的文件内容运行回调中的代码$_
,然后覆盖该文件。† 还有edit_lines
将给定代码一次应用于一行的。这些行为都不完全像-i
命令行中的,但这不是缺点。
我将代码放在一个{}
块中以定位该$dog_cnt
计数器。另一种选择是在回调中定义该变量,特别是当周围的代码不需要计数器时。
sub {
my $dog_cnt = 0;
s/Dog_Image_\K([0-9]+)\.jpg/++$dog_cnt . '.jpg'/ge
}
那么该方法edit_lines
将不适用于现有的代码,因为回调会针对每一行运行,因此计数器始终被重新定义为零。请根据需要进行更改。
或者,正常编辑文件 – 打开、逐行处理、以您选择的方式覆盖原始文件,†之后进行您想要的任何检查。代码不多,只有几行。它比从脚本中运行复杂的 shell 命令好得多。更不用说运行命令perl
行程序了。
† 该库没有说明它如何“覆盖”文件,但在我的测试中,inode 编号发生了变化,因此它会写出一个包含更改内容的文件,然后在原始文件上重命名。
如果 inode 编号需要保持不变(有时文件上使用的工具需要这样做),则可以通过照常打开和处理文件来更改文件,并将新版本写入临时文件或将其保存在内存中。
然后打开原始文件进行写入(这会截断它)并将新内容写入其中(从临时文件或内存中,无论您将其存放在何处)。现在原始文件的内容已更改,但文件的 inode 编号未更改。如果有临时文件,请将其删除。
0
|
以下是在命令行上执行此操作的一种方法(这在我的 shell 中有效):
perl -pi -e 's/Dog_Image_.*.jpg/"Dog_Image_" . ++$i . ".jpg"/e' Animals.txt
它会覆盖原始文件。
引用至关重要。关键是将固定字符串与替换侧的执行代码分开。我使用.
字符串连接运算符来实现这一点。
您的尝试存在很多问题。您将命令行 Perl 与文件中的 Perl 代码混合在一起。
3
-
1nit:这不会覆盖原始文件。它会创建一个新文件并重命名,然后取消链接原始名称。这有时是一个微妙的区别,但有时却极其重要。
– -
这在 shell 中对我有用,但在我的 perl 脚本中却不行,是否有特定的方法可以格式化它以使其在脚本中工作?
– -
@TreyB 只需使用
while(<>)
循环。实现 有点棘手-i
,但你真的、真的、真的不想这样做。编写你的工具作为简单的过滤器并处理 shell 中的重命名。
–
|
"Dog_Image_.++$i.jpg"
不是有效的 Perl 代码。"Dog_Image_" . ++$i . ".jpg"
将是。
但您还有许多其他错误。已修复:
#!/usr/bin/perl
use strict;
use warnings;
exec( "perl", "-i", "-pe" 's/Dog_Image_\K.*(?=\.jpg$)/++$i/se', "Animals.txt" );
切换到 shell 脚本更简单。
#!/usr/bin/sh
exec perl -i -pe's/Dog_Image_\K.*(?=\.jpg$)/++$i/se' Animals.txt
|
"
替换字符串中有一个不匹配的内容。–
perl
在另一个 perl 脚本中使用该语句,那是一个 shell 命令。–
–
–
.++$i
应该放在引号里。应该是"Dog_Image_" . ++i . ".jpg"
–
|