简体   繁体   English

Perl单词不发音:删除除第一个和最后一个之外的所有元音

[英]Perl word disenvoweling: removing all vowels except the first and last

In order to shorten a number of names, but still keep them somewhat readable, I would like to remove all vowels from strings, except for the first and last occurrence. 为了缩短名称的数量,但仍使它们保持一定的可读性,我想从字符串中删除所有元音,除了第一个和最后一个出现。 For example, I'd like 'Minnesota' to become 'Minnsta'. 例如,我希望'Minnesota'成为'Minnsta'。

my $name="Minnesota";

I've tried to make use of Perl's zero-width look-behind regex syntax, like so: 我试图利用Perl的零宽度后向正则表达式语法,如下所示:

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

However, although this properly takes care of the first vowel, it removes the last one. 但是,尽管这可以正确处理第一个元音,但会删除最后一个。 To fix this, I tried to keep the last vowel in place, like this: 为了解决这个问题,我尝试将最后一个元音保留在原位,如下所示:

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

This also didn't work, presumably because the '$' anchors the whole regex to the end of the string. 这也不起作用,大概是因为“ $”将整个正则表达式锚定在字符串的末尾。

Of course, I could look up the position of the first vowel, reverse the rest of the string and remove all vowels except for the 'first' (last), and re-reverse and concatenate the strings, but that's not very elegant. 当然,我可以查找第一个元音的位置,反转字符串的其余部分,并除去“ first”(最后一个)之外的所有元音,然后重新反转并连接字符串,但这不是很优雅。 I feel I'm overlooking one of the options of the zero-width syntax. 我觉得我忽略了零宽度语法的选项之一。

Just specify a ending boundary condition for your regex: (?![^aeiou]*$) : 只需为您的正则表达式指定结束边界条件: (?![^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;
}

Outputs: 输出:

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

For me, this one works (the '1' in front is intentional): 对我来说,这是可行的(前面的“ 1”是故意的):

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

if you want to keep a minimum length of $name (eg 3): 如果要保留$ name的最小长度(例如3):

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

Instead of writing 'AEIOUaeiou' you can of course use the 'i' flag to ignore the case. 当然,除了写“ AEIOUaeiou”外,您还可以使用“ i”标志来忽略大小写。 I wrote it down explicitly for easier reading. 我将其明确写下来以方便阅读。

You can of course put any characters in the brackets. 您当然可以将任何字符放在方括号中。

Make sure that there is a vowel after the MATCH, but exclude it from the MATCH. 确保在MATCH之后有一个元音,但不要将其从MATCH中排除。

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

The substitutions done by your regexp are: 您的正则表达式所做的替换是:

  • Minnesota => nne -> nn => Minnsota 明尼苏达州=> nne-> nn =>明尼苏达州
  • Minnsota => nnso -> nns => Minnsta 明尼苏达州=> nnso-> nns =>明尼斯塔
  • Minnsta => nnsta -> nnst => Minnst Minnsta => nnsta-> nnst => Minnst
  • Minnst => nnsta -> nnst => Minnst Minnst => nnsta-> nnst => Minnst

So the last substitution swaps 'nnsta' with 'nnst'. 因此,最后一个替换将'nnsta'与'nnst'交换。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM