这会导致错误“修改在...尝试的只读值”
$mfgs = "AUDBMWCH-FO-TOY";
while( $mfgs =~ /(.{3})/g ) {
print $1 =~ s/-// . "\n";
}
如何在不添加额外行的情况下执行此操作?到目前为止,我可以告诉Perl没有内置的str_replace()
函数。我可以写一个,但正如我所说,我试图找出如何做到这一点,没有额外的代码行。
这不是在实际项目中使用。这仅用于学习目的。
答案 0 :(得分:6)
$mfgs = "AUDBMWCH-FO-TOY";
while( $mfgs =~ /(.{3})/g ) {
print $1 =~ s/-// . "\n";
}
只是一次读取$mfgs
字符串三个字符并删除连字符。
可以重新编写以下内容:
say for map { s|-||r } $mfgs =~ /.../g ; # Works in Perl 5.14+
use List::MoreUtils 'apply';
say for apply { s|-|| } $mfgs =~ /.../g ; # If that 'r' flag isn't there
或使用音译操作符(tr///
)看到没有任何固有的regexy正在进行:
say for map tr!-!!dr , $mfgs =~ /.../g ;
如果三个字符的块中最多只有一个连字符,则两种方式都会产生相同的结果。这是因为tr/-//dr
会删除所有连字符,而s/-//r
只会删除第一次出现的连字符。
这回答了人们如何做到这一点,所以让我们看看为什么它在
之前无效$1
?根据perldoc perlvar
(强调补充):
<强>
$<digits> ($1, $2, ...)
强>包含相应捕获集的子模式 来自上一次成功模式匹配的括号,不计算在内 已经退出的嵌套块中匹配的模式。
这些变量是 只读 且动态范围。
换句话说,$1
无法修改,这是s///
试图做的事情。
但是,$1
的副本可以进行修改,Jonathan Leffler's solution会对此进行修改。
答案 1 :(得分:3)
我不确定您为什么要这样做 - 数据结构与以下相比是次优的:
my @mfgs = ( "AUD", "BMW", "CH", "FO", "TOY" );
然而,这有效:
use strict;
use warnings;
my($mfgs, $x) = ("AUDBMWCH-FO-TOY");
while ($mfgs =~ /(.{3})/g)
{
printf "%s\n", ($x = $1, $x =~ s/-//, $x);
}
如果没有限制或警告,您可以使用:
my $mfgs = "AUDBMWCH-FO-TOY";
while ($mfgs =~ /(.{3})/g)
{
printf "%s\n", ($x = $1, $x =~ s/-//, $x);
}
但是,最好不要费心学习如何在没有use strict;
和use warnings;
(或use diagnostics;
)的情况下使用Perl。
答案 2 :(得分:3)
在Perl 5.14中,有一个新的/r
修饰符可用于s///
替换(以及tr///
/ y///
音译),这会导致返回的结果为一个新的字符串,不会改变原文。
use 5.014;
$mfgs = "AUDBMWCH-FO-TOY";
while ($mfgs =~ /(.{3})/g) {
say $1 =~ s/-//r;
}
答案 3 :(得分:2)
print( do { ( my $x = $1 ) =~ s/-//; $x }, "\n" );
print( ( apply { s/-// } $1 ), "\n" );
say( do { ( my $x = $1 ) =~ s/-//; $x } ); # 5.10+
say( apply { s/-// } $1 ); # 5.10+
say( $x =~ s/-//r ); # 5.14+
apply
来自List::MoreUtils。
答案 4 :(得分:2)
如何在不添加额外行的情况下执行此操作?据我所知 Perl没有内置的str_replace()函数。我可以 写一个,但正如我所说,我试图弄清楚如何做到这一点 没有额外的代码行。
您是否阅读过perlfunc?此外,这不是关于函数,它是$1
是只读变量。请参阅perldoc perlvar。
$<digits> ($1, $2, ...)
包含相应捕获集的子模式 来自上一次成功模式匹配的括号,不计算在内 已经退出的嵌套块中匹配的模式。
这些变量是只读的和动态范围的。
尽我所知,这是实现相关代码的最经济方式:
tr/-//d, say for $mfgs =~ /.{3}/g;
或长版:
my $mfgs = "AUDBMWCH-FO-TOY";
for my $str ($mfgs =~ /.{3}/g) {
$str =~ tr/-//d;
say $str;
}
请注意,在这种情况下不需要捕获括号。来自perldoc perlop:
/ g修饰符指定全局模式匹配 - 即匹配 字符串中尽可能多的次数。它的表现取决于 上下文。在列表上下文中,它返回子字符串的列表 与正则表达式中的任何捕获括号匹配。如果 没有括号,它返回所有匹配的列表 字符串,好像整个模式周围都有圆括号。
另请注意while
和for (foreach)
之间的区别。 while
将在匹配时迭代(在标量上下文中使用/g
),隐式使用\G
断言,但不会将匹配存储在变量中(除了{ {1}})。 $1
会一次提取所有匹配项(在列表上下文中使用for
),匹配项将在循环变量(/g
中显示为第一种情况,$_
在第二个)。
在标量上下文中,m // g的每次执行都会找到下一个匹配项, 如果匹配则返回true,如果没有进一步匹配则返回false。 可以使用pos()读取或设置最后一次匹配后的位置 功能;见pos。失败的匹配通常会重置搜索位置 到字符串的开头,但你可以通过添加来避免这种情况 / c修饰符(例如m // gc)。修改目标字符串也会重置 搜索位置。
答案 5 :(得分:0)
您可以随时执行此操作以获取由分隔符分割的项目数组。
@a = split("-", $mfgs);
要str_replace,请使用
$var =~ s/search/replace/g;
喜欢这样
$mfgs =~ s/-/\n/g;
printf("%s\n", $mfgs);