C# - 除了字符串的第一个和最后一个字符,使用正则表达式删除字符串中的元音字母

3
我正在尝试从一个字符串中删除除第一个和最后一个字符以外的所有元音字母。我已经试过了两种表达式和两种方法,但都失败了。我在下面描述了它们。有没有人有这个问题的正则表达式?
例如:
原始字符串 -- source = apeaple 正则表达式后 -- source_modified = apple (这就是预期的结果)
我尝试了表达式 ([a-zA-Z])[aeiouAEIOU]([a-zA-Z]),但是这个表达式也会去掉重复字符。所以当我应用上面的表达式时,以下情况发生:
使用的代码 --
Regex reg = new Regex("([a-zA-Z])[aeiouAEIOU]([a-zA-Z])"); string source_modified = reg.Replace(source, "");
原始字符串 -- source = apeaple 代码执行后 -- source_modified = aple(重复字符被删除)
我还尝试了 ([a-zA-Z])[aeiouAEIOU]*([a-zA-Z]),但这只会删除一个元音字母而不是所有元音字母。所以当我应用上述表达式时,以下情况发生:
使用的代码 --
Regex reg = new Regex("([a-zA-Z])[aeiouAEIOU]*([a-zA-Z])"); string source_modified = reg.Replace(source, "");
原始字符串 -- source = apeaple 代码执行后 -- source_modified = ""(所有字符都被删除)
我还尝试了 string source_modified = Regex.Replace(source, "([a-zA-Z])[aeiouAEIOU]*([a-zA-Z])", "$1" + "$2");,但这只会删除一个元音字母而不是所有元音字母。所以当我应用上述表达式时,以下情况发生:
使用的代码 --
string source_modified = Regex.Replace(source, "([a-zA-Z])[aeiouAEIOU]*([a-zA-Z])", "$1" + "$2");
原始字符串 -- source = apeaple 代码执行后 -- source_modified = apeple

等一下 - 如果你想删除除第一个和最后一个字符以外的所有元音字母apeaple -> apeple 是错误的!应该是apeaple -> apple,对吗? - Ani
1
正则表达式不是猜谜游戏,哈哈。使用GUI工具来帮助测试(和学习),例如http://www.radsoftware.com.au/regexdesigner/。 - banging
值得注意的是,([a-zA-Z])[aeiouAEIOU]([a-zA-Z])没有删除双字母,但却删除了元音字母以及它前后的字母(这是您正在匹配并用空值替换的内容)。这导致删除了两个元音字母以及其中一个P,但与重复无关。 - Chris
@Chris;哦,好的..!! 我原本以为不是这样的..!! 无论如何,感谢你指出来..!! - samar
那只是一条注释,不是完整的解决方案。它是完整解决方案的一部分。我认为buckley的答案是正确的。 - paparazzo
显示剩余3条评论
4个回答

7
如果可以的话,为什么不删除第一个和最后一个字符,去掉元音字母,然后再拼接起来呢?
string sWord = "apeaple";
char cFirst = sWord[0], cLast = sWord[sWord.length-1];

sWord = sWord.substring(1, sWord.length -2);

sWord = cFirst.ToString() + 
        Regex.Replace(sWord , "[aouiyeAOUIYE]", String.Empty) + 
        cLast.ToString();

这当然是一个有效的解决方案,但我更喜欢下面的巴克利,因为它更整洁一些(尽管正则表达式更丑陋)。对于似乎不太熟悉正则表达式及其作用的OP来说,这肯定是最好的选择。 - Chris
@Shai;这看起来是一个不错的选择。但也许这只是一个变通方法。有没有比这更好的解决方案?? - samar
@samar,看看Buckley的答案-它有效而且只用了一行代码(几乎是),你应该接受它。 - Shai

7
你需要这样一些lookaround。
(?<!^)[aouieyAOUIEY](?!$)

C#支持该技术,并且非常强大。
string resultString = null;
try {
    resultString = Regex.Replace(subjectString, "(?<!^)[aeui](?!$)", "");
} catch (ArgumentException ex) {
    // Syntax error in the regular expression
}

更新1

T.W.R.Cole告诉我,在英语中有一条特殊规则(“对于像“Anyanka”这样使用内部“y”作为辅音的单词,此方法无效”)

以下更改应该可以解决这个问题,使用负向先行断言技术:

(?<!^)([aouie]|y(?![aouie]))(?!$)

这次开启正则表达式的修饰符以忽略大小写匹配,这会使正则表达式比原来更简单。

如果一个y后面紧跟着另一个y仍然表示y是辅音(嗯...有这样的词吗),因此不应该消失,那么y也必须列在最后一个字符类中:

(?<!^)([aouie]|y(?![aouiey]))(?!$)

我再次强调,我使用的是C#作为我的正则表达式方言,它对于环视技术有很好的支持。


1
这个工作得非常好..!! 需要检查其他元音的组合,但我认为它会完美地工作..!! 谢谢你百万次..!! :) - samar
这不适用于像“Anyanka”这样使用内部'y'作为辅音的单词。要找到元音'y',您需要消除后面跟随元音的'y'。 - T.W.R. Cole
@T.W.R.Cole 我之前不熟悉英语中这样的规则。我已经更新了我的答案以支持它。 - buckley

0

你需要以至少一个字符开头,找到一个元音字母,然后以至少一个字符结束字符串。尝试:

(.+)[aeiouAEIOU](.+)

这看起来不会有太大帮助... 如果你用 $1$2 替换,那么在我的测试中它并不能做正确的事情... 如果你用空白替换,那么当然它会移除所有东西... - Chris
你得到了什么结果? - Eliot Ball
如果我没记错的话,只是从中间剥离一个字符,这大概是我所期望的。为什么?你得到了什么结果? - Chris
如果您重复应用此操作直到不匹配,则应该可以解决问题。 - Eliot Ball
啊,好的。我现在明白你的想法了。由于最初的问题假设任何正则表达式都只是单一使用,所以你可能应该把所有的循环内容都放进去。如果你这样做,最好只用 . 而不是 .+,并在元音字母上加上一个 +(即 (.)[aeiouAEIOU]+(.))。由于贪婪匹配的原因,你的代码每次运行只会进行一次替换,并且只会删除一个元音字母。而我的修改版将获取多个元音字母,并一次只消耗一个其他字符。当然,其他答案可能更好。 - Chris
是的,我当时是在 Perl 方面考虑的,那里只需要使用 s/(.+)aeiouAEIOU/$1$2/g 就可以轻松删除所有元音字母,但这种方法在 .NET 中并不适用。我同意其他答案更好,感谢您的反馈。 - Eliot Ball

0

如果您想将此应用于由多个单词组成的字符串中的单个单词,\B[AEIOUaeiou]\B 可能值得一试。 \B 是非单词边界,即两个相邻字符都是单词字符或两个非单词字符的任何位置。如果在两个位置之间有元音字母,则显然不可能是后一种情况。

不用说,它也适用于仅由一个单词组成的字符串。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接