Perl word disenvoweling:删除除第一个和最后一个之外的所有元音

时间:2014-08-07 18:41:36

标签: regex perl regex-lookarounds last-occurrence

为了缩短一些名字,但仍然保持一定的可读性,我想从字符串中删除所有元音,除了第一次和最后一次出现。例如,我喜欢'明尼苏达州'成为Minnsta'。

my $name="Minnesota";

我尝试使用Perl的零宽度后视正则表达式语法,如下所示:

$name =~ s/(?<=[aeiou])([^aeiou]*)[aeiou]/$1/ig; # minnst

然而,虽然这适当地处理了第一个元音,但它删除了最后一个元音。 为了解决这个问题,我试着保留最后一个元音,如下所示:

$name =~ s/(?<=[aeiou])([^aeiou]*)([aeiou])([aeiou][^aeiou]*)$/$1$3/ig; # minnesota

这也没有用,大概是因为&#39; $&#39;将整个正则表达式锚定到字符串的末尾。

当然,我可以查找第一个元音的位置,反转其余的字符串并删除所有元音,除了“第一个元音”。 (最后),并重新反转和连接字符串,但这不是很优雅。我觉得我忽略了零宽度语法的一个选项。

3 个答案:

答案 0 :(得分:2)

只需为正则表达式指定结束边界条件:(?![^aeiou]*$)

use strict;
use warnings;

my @words = qw(Minnesota concatenate strings elegant I feel overlooking options syntax any greatly appreciated);

for (@words) {
    my $word = $_;

    $word =~ s/(?<=[aeiou])([^aeiou]*)[aeiou](?![^aeiou]*$)/$1/ig;

    printf "%-12s -> %s\n", $_, $word;
}

输出:

Minnesota    -> Minnsta
concatenate  -> conctnte
strings      -> strings
elegant      -> elgant
I            -> I
feel         -> feel
overlooking  -> ovrlking
options      -> optons
syntax       -> syntax
any          -> any
greatly      -> greatly
appreciated  -> apprcted

答案 1 :(得分:1)

对我来说,这个有效(前面的'1'是故意的):

1 while ($name =~ s/^(.+)[AEIOUaeiou]/$1/g );

如果你想保留$ name的最小长度(例如3):

1 while (length $name > 3 && $name =~ s/^(.+)[AEIOUaeiou]/$1/g );

您可以使用'i'标志来忽略此情况,而不是写'AEIOUaeiou'。我明确地写下来以便于阅读。

您当然可以在括号中添加任何字符。

答案 2 :(得分:0)

确保在MATCH之后有一个元音,但将其从MATCH中排除。

$name =~ s/(?<=[aeiou])([^aeiou]*)[aeiou](?=.*[aeiou])/$1/ig;

正则表达式完成的替换是:

  • 明尼苏达州=&gt; nne - &gt; nn =&gt; Minnsota
  • Minnsota =&gt; nnso - &gt; nns =&gt; Minnsta
  • Minnsta =&gt; nnsta - &gt; nnst =&gt; Minnst
  • Minnst =&gt; nnsta - &gt; nnst =&gt; Minnst

所以最后一次替换用'nnst'交换'nnsta'。

my $name="Minnesota";
my $prev = '';
while ( $name ne $prev ) {
    $prev = $name;
    $name =~ s/(?<=[aeiou])([^aeiou]*)[aeiou]/$1/i;
    print "$prev => ${^MATCH} -> $1 => $name\n";
}