使用正则表达式从字符串中提取去除的(1个元音,1个辅音)单词

-1 投票
1 回答
606 浏览
提问于 2025-04-17 23:06

注意:我正在学习正则表达式(regex),虽然我知道在这种情况下正则表达式不是最好的解决方案,但我还是想了解一下它是否可行。

任务:

你会得到一段包含不同单词的文本。这些单词之间用空格和标点符号分开。在这个任务中,数字不算作单词(字母和数字混合的也不算)。你需要计算那些元音和辅音交替出现的单词数量,也就是说,你计算的单词不能有两个连续的元音或辅音。由单个字母组成的单词不算在内——不要计算这些。字母的大小写在这个任务中不重要。

输入:一段文本,作为字符串(unicode格式)

输出:交替单词的数量,作为一个整数。

例如:

string1 = "Dog,cat,mouse,bird.Human." 应该返回 3。

1 个回答

2

我觉得有两种主要的方法来实现这个目标,首先要检查元音和辅音是否交替出现。

比如说,要检查字母 ab 是否交替出现,你可以用这样的方式:

a(?:ba)+|b(?:ab)+

如果把这个方法扩展到元音和辅音,你就会得到一个比较长的正则表达式:

(?<![a-z])(?:[aeiou](?:[^P{L}aeiou][aeiou])+|[^\P{L}aeiou](?:[aeiou][^\P{L}aeiou])+)(?![a-z])

正则表达式演示

这里有两个负向前瞻 (?<![a-z])(?![a-z]),它们的作用是作为单词的边界,确保整个单词都被检查。

[aeiou] 是用来表示元音的,而 [^P{L}aeiou] 是用来表示辅音的。它相当于 [b-df-hj-np-tv-z]

第二种方法是确保单词中没有连续的元音或辅音。这种方法需要另一个负向前瞻,但相对较短:

(?<![a-z])(?:(?![aeiou]{2}|[^\P{L}aeiou]{2})[a-z])+(?![a-z])

正则表达式演示

你可以使用 re.findall 并激活 re.I(或者在正则表达式开头使用 (?i))来获取所有匹配的结果,然后计算列表的长度来得到“条纹单词”的数量。

(?<![a-z])              # Ensure no letter before
  (?:
    (?!
      [aeiou]{2}        # Ensure no two consecutive vowel
    |
      [^\P{L}aeiou]{2}  # Ensure no two consecutive consonant
    )
    [a-z]               # Any letter
  )+
(?![a-z])               # Ensure no more letters

撰写回答