我正在寻找一个 grep 参数来在文本中查找具有元音-辅音-同元音模式的单词。
例子:
奥罗
烯罗
ofo
点对点珍珠棉点对点
谢谢。
答案1
请注意,元音的构成因语言和地区而异。
对于公认的英语元音(这里只考虑小写版本):
vowels=aeiou
consonants=bcdfghjklmnpqrstvwxyz
grep "\([$vowels]\)[$consonants]\1"
您可以适应$vowels
您$consonants
的语言。
然而,对于 Unicode,它可能会变得有点复杂。
例如,即使我们限制为拉丁字母,在法语中,它也会匹配夏天这个词:été。然而,在 Unicode 中,é 可以写成单个字符 (U+00E9 é
) 或分解形式e
后跟其结合尖锐的口音(◌́
U+0301)。
另外,还有这样的字符fi
,这是 2 个字符的另一种写法fi
。
解决这个问题的一种方法是将文本转换为标准化形式在检查之前将它们扩展为多字符形式(然后我们需要考虑基本字符及其变音符号或其他组合字符的序列(完整的字形簇,如e⃞
!= é̂
)。
perl -MUnicode::Normalize -C -lne '
print if NFKD($_) =~ /((?=[aeiouy])\X)(?=[bcdfghjklmnpqrstvwxz])\X\1(?!\p{mark})/'
(NKFD 是标准化形式兼容性分解é
,变成e
+◌́
和+fi
的那个)。f
i
\X
在perl
比赛中扩展字素簇。(?=[aeiouy])\X
基本字符为小写拉丁元音(soe
或é
...)的字素簇也是如此。这里包括y
作为元音(因为在许多使用拉丁字母的语言中它被认为是元音)。
因此,我们匹配元音簇,后跟辅音簇,然后是 中捕获的第一个簇\1
,但我们需要确保下一个字符仍然不是该簇的一部分,否则它会匹配诸如 之类的内容eté
。因此,使用负前瞻运算符来检查下一个字符是否不具有该mark
属性。
因此,对于这样的输入:
fini
été
tacheté
它返回:
fini
été