仍然在教自己Perl。我正在尝试编写一些代码来计算包含双字母的文件行,然后在这些双字母周围放置括号。
现在我想出的是第一次出现双字母,但没有找到任何其他字母。例如,如果该行是:
Amp,James Watt,Bob Transformer等。这些开拓者进行了很多次
我的代码会渲染:
19安培,James Wa(tt),Bob Transformer等。这些开拓者进行了许多
“19”是计数(包含双字母的行),它得到“瓦特”的“tt”但是错过了“先锋”中的“ee”。
以下是我的代码:
$file = '/path/to/file/electricity.txt';
open(FH, $file) || die "Cannot open the file\n";
my $counter=0;
while (<FH>) {
chomp();
if (/(\w)\1/) {
$counter += 1;
s/$&/\($&\)/g;
print "\n\n$counter $_\n\n";
} else {
print "$_\n";
}
}
close(FH);
我在俯瞰什么?
答案 0 :(得分:4)
use strict;
use warnings;
use 5.010;
use autodie;
my $file = '/path/to/file/electricity.txt';
open my $fh, '<', $file;
my $counter = 0;
while (<$fh>) {
chomp;
if (/(\w)\1/) {
$counter++;
s/
(?<full>
(?<letter>\p{L})
\g{letter}
)
/($+{full})/xg;
$_ = $counter . ' ' . $_;
}
say;
}
你忽视了一些事情。 strict and warnings; say的5.010(或更高!); autodie所以你不必继续输入那些'或死'; Lexical filehandles和three-argument form of open;有点挑剔,但knowing when (not) to use parens for function calls;了解你shouldn't use $&的原因; autoincrement operator ..
但特别是在正则表达式部分, $&amp;只设置匹配(m //),而不是替换实际上没有,ysth像往常一样正确。遗憾!
(我冒昧地修改你的正则表达式;它使用了命名的捕获 - (?)而不是裸露的parens,通过正则表达式中的\ g {}符号访问,以及外部的%+哈希它 - 和Unicode风格的属性 - \ p {Etc})。关于perlre和perluniprops中的人的更多信息。
答案 1 :(得分:3)
您需要使用后退参考:
#! /usr/bin/env perl
use warnings;
use strict;
my $line = "this is a doubble letter test of my scrippt";
$line =~ s/([[:alpha:]])(\1)/($1$2)/g;
print "$line\n";
现在是测试。
$ ./test.pl
this is a dou(bb)le le(tt)er test of my scri(pp)t
有效!
当您进行替换时,使用$1
来表示括号中的内容。当您引用正则表达式本身的一部分时,使用\1
表单。
[[:alpha:]]
是一个特殊的POSIX类。您可以通过输入
$ perldoc perlre
在命令行。
答案 2 :(得分:2)
你通过弄乱$&
来使事情过于复杂。 s///g
返回在标量上下文中使用时执行的替换次数,因此您可以一次性完成所有操作而无需手动计算匹配或跟踪每个匹配的位置:
#!/usr/bin/env perl
use strict;
use warnings;
my $text = 'James Watt, a pioneer of wattage engineering';
my $doubles = $text =~ s/(\w)\1/($1$1)/g;
print "$doubles $text\n";
输出:
4 James Wa(tt), a pion(ee)r of wa(tt)age engin(ee)ring
编辑: OP在评论中表示相关练习不使用=~
,因此这里是一个非正则表达式的解决方案,因为所有正则表达式匹配都使用{{1} (隐式或显式):
=~
答案 3 :(得分:1)
问题是你正在使用$&amp;在第二个正则表达式中,它只匹配双字母集的第一次出现
if (/(\w)\1/) { #first occurance matched, so the pattern in the replace regex will only be that particular set of double letters
尝试做这样的事情:
s/(\w)\1/\($1$1\)/g;
代替s/$&/\($&\)/g;
编辑后的完整代码:
$file = '/path/to/file/electricity.txt';
open(FH, $file) || die "Cannot open the file\n";
my $counter=0;
while (<FH>) {
chomp();
if (s/(\w)\1/\($1$1\)/g) {
$counter++;
print "\n\n$counter $_\n\n";
} else {
print "$_\n";
}
}
close(FH);
请注意,您可以在条件语句中使用s /// g replace,当发生替换时该条件语句为true。