首先,其中大部分不是 Perl,也不是任何编程语言。我建议您首先阅读您选择的 Perl 教程,然后再尝试获取特定问题的解决方案。不过,这里有一个答案,因为这个问题本身就足够引起人们的兴趣。
接下来,在 Perl 中你不能直接索引到一个字符串,所以你不能像这样跳过第一个字符。
当然,您可以将字符串中的第一个字符分开并处理其余字符(删除元音)。正则表达式的一种方法†
use warnings;
use strict;
use feature 'say';
my $str = shift // 'out with ALL vowels after first';
$str =~ s/.\K(.*)/ $1 =~ tr{[aeiouAEIOU]}{}dr /e;
say $str; #--> ot wth LL vwls ftr frst
这依赖于/e 修饰符,这使得替换端被评估为代码,因此它在那里运行一个独立的transliteration (tr),处理捕获的子字符串。
然后我们需要嵌入的tr/regex 中的/r modifier,以返回新字符串,而不是更改旧字符串——无论如何,这是不可能的无法更改$1。
也可以使用tr 的正则表达式,效率较低,但有很多便利
$str =~ s/.\K(.*)/ $1 =~ s{[aeiou]}{}igr /e;
现在我们可以在该正则表达式中使用比tr 更复杂的工具;在这种情况下,它只是 i 标志,用于区分大小写-insensitive。
如果要保留的第一个字符不止一个,请将 . 更改为 .{N}。
† 当然,Regex 不是强制性的。更基本的做法:split 将字符串转换为第一个字符和其余部分,然后在其余部分使用 tr
use warnings;
use strict;
use feature 'say';
my $str = shift // q(out with ALL vowels after first);
my ($result, $rest) = split //, $str, 2; # first char, rest of string
$result .= $rest =~ tr/aeiouAEIOU//dr; # prune $rest of vowels, append to $result
say $result;
然后把它放在一个小的迷你子程序中。要更改原始字符串,而不是获取新的 ($result) 字符串,请在任何地方使用它 ($str) 而不是 $result。
我不确定它如何比较效率,但它可能会很好。
为了好奇,这里只写一个声明
$str = join '', map { length > 1 ? tr/aeiouAEIOU//dr : $_ } split //, $str, 2;
这特别使用了只需要跳过第一个(一个)字符的事实;只要标准确实涉及子字符串的长度,这很容易实现动态化。
更重要的是,这假设字符串的其余部分长于 1 个字符。要放弃该假设,请更改标准
use feature 'state';
$str = join '', map {
state $chr_cnt = 0;
++$chr_cnt > 1 ? tr/aeiouAEIOU//dr : $_
}
split //, $str, 2;
这也依赖于只保留一个字符。它使用feature 在执行过程中保持一个词法值state。
更通用的解决方案,它使用substr 的属性可以写入
substr($str, 1) =~ tr/aeiouAEIOU//d;
在这里放宽对第一个字符的限制更加简洁:只需更改 1 即可跳过更多字符。棘手的——意想不到的——部分可能是通常内置函数不能像那样写入,它们不是lvalue subroutines