将单词中的字母分类为元音和辅音

To classify letters in words as vowels and consonants

给定一个单词,我需要一个函数 returns 根据元音和辅音来构造单词的结构。 “c”代表辅音,“v”代表元音。如果字母“y”是单词的首字母,则为辅音,否则为元音。例如,wordClass("dan​​ce") returns "cvccv" 和 wordClass("yucky") returns "cvccv".

我试过了,但可能有更有效的方法:

Function wordClass(word As String) As String
    Dim vowels(1 To 6) As String, vowelsNoY(1 To 5) As String, consonants(1 To 22) As String, pattern(1 To 5) As String
    Dim i As Integer, j As Integer
    
    vowels(1) = "a"
    vowels(2) = "e"
    vowels(3) = "i"
    vowels(4) = "o"
    vowels(5) = "u"
    vowels(6) = "y"
    
    vowelsNoY(1) = "a"
    vowelsNoY(2) = "e"
    vowelsNoY(3) = "i"
    vowelsNoY(4) = "o"
    vowelsNoY(5) = "u"
    
    consonants(1) = "b"
    consonants(2) = "c"
    consonants(3) = "d"
    consonants(4) = "f"
    consonants(5) = "g"
    consonants(6) = "h"
    consonants(7) = "j"
    consonants(8) = "k"
    consonants(9) = "l"
    consonants(10) = "m"
    consonants(11) = "n"
    consonants(12) = "p"
    consonants(13) = "q"
    consonants(14) = "r"
    consonants(15) = "s"
    consonants(16) = "t"
    consonants(18) = "v"
    consonants(19) = "w"
    consonants(20) = "x"
    consonants(21) = "y"
    consonants(22) = "Z"
    
    For h = 1 To Len(consonants)
    
        If StrComp(Mid(word, 1, 1), vowelsNoY(h), vbTextCompare) = 0 Then
            pattern(1) = "v"
        ElseIf StrComp(Mid(word, 1, 1), consonants(h), vbTextCompare) = 0 Then
            pattern(1) = "c"
        End If
    
    Next h
        
    For i = 2 To Len(word)
        
        For j = 2 To Len(word)
            If StrComp(Mid(word, i, 1), vowels(j), vbTextCompare) = 0 Then
                pattern(j) = "v"
            ElseIf StrComp(Mid(word, i, 1), consonants(j), vbTextCompare) = 0 Then
                pattern(j) = "c"
            End If
        Next j
    Next i
            
    wordClass = CStr(pattern)
    
End Function

我会用这样的东西。将此复制到新模块:

Public strVowels As String
Public arrVowels() As String

Public Function wordClass(strWord As String, Optional blnIncludeY As Boolean = False) As String

Dim lngLetter As Long

    setup blnIncludeY
    
    For lngLetter = 1 To Len(strWord)
        If lngLetter = 1 And LCase(Left(strWord, 1) = "y") Then
            wordClass = "C"
        Else
            If isVowel(Mid(strWord, lngLetter, 1)) Then
                wordClass = wordClass & "V"
            Else
                wordClass = wordClass & "C"
            End If
        End If
    Next lngLetter
    
End Function

Public Sub setup(blnIncludeY As Boolean)

strVowels = "a;e;i;o;u"
If blnIncludeY Then strVowels = strVowels & ";y"

arrVowels = Split(strVowels, ";")

End Sub

Public Function isVowel(strLetter As String)
    isVowel = Not IsError(Application.Match(LCase(strLetter), arrVowels, False))
End Function
Option Explicit

Public Sub Example()
    Debug.Print wordClass("dance")
    Debug.Print wordClass("yucky")
End Sub


Public Function wordClass(ByVal word As String) As String
    Const vowels As String = "aeiouy"
    Const vowelsNoY As String = "aeiou"
    Const consonants As String = "bcdfghjklmnopqrstvwxyz"
    
    Dim retval As String

    Dim i As Long
    For i = 1 To Len(word)
        Dim char As String
        char = Mid$(word, i, 1)
        
        If i = 1 Then
            If InStr(vowelsNoY, char) Then
                retval = retval & "v"
            ElseIf InStr(consonants, char) Then
                retval = retval & "c"
            Else
                retval = retval & "-"
            End If
        Else
            If InStr(vowels, char) Then
                retval = retval & "v"
            ElseIf InStr(consonants, char) Then
                retval = retval & "c"
            Else
                retval = retval & "-"
            End If
        End If
    Next i
    
    wordClass = retval
End Function

我不会定义数组,只是使用 Instr 检查字符是否在元音内。要检查辅音,我会检查该字符是否不是元音字母并且它位于“b”和“z”之间 - 否则它是其他字符。

“效率”对我来说主要是可读性问题——无论你使用哪种尝试,一切都在内存中完成,除非你想分析数百万个单词,否则不需要优化速度。

我也检查第一个字符。如果它是“y”,我将其硬编码为辅音并以第二个字符开始循环。

这是我的尝试:

Function wordClass(ByVal word As String) As String
    Dim i As Long, startIndex As Long
    Const vowels = "aeiouy"
    Const vowel = "V"
    Const consonant = "C"
    Const other = "?"
    
    word = LCase(word)
    If Left(word, 1) = "y" Then
        wordClass = consonant
        startIndex = 2
    Else
        wordClass = ""
        startIndex = 1
    End If
    
    For i = startIndex To Len(word)
        Dim c As String
        c = Mid(word, i, 1)
        If InStr(vowels, c) > 0 Then
            wordClass = wordClass & vowel
        ElseIf c > "a" And c <= "z" Then
            wordClass = wordClass & consonant
        Else
            wordClass = wordClass & other
        End If
    Next

End Function

您可以使用正则表达式分两步完成此操作。 Regex 可以在字符串中搜索单个字母,然后用“c”或“v”替换所有匹配的字母。 你会有 2 个模式和 2 个替换,然后就完成了。

模式 1:"[bcdfghjklmnpqrstvwxz]|^y":匹配该列表中的任何字符或前导 y。

模式 2:"[aeiouy]":匹配该列表中的任何字符

由于首先应用模式 1,因此可以安全地将所有剩余的 y 假定为元音。此外,由于第一个模式将所有辅音更改为“c”,因此它们不会匹配模式 2,而是 double-transformed。如果您首先 运行 元音正则表达式并将字母更改为“v”,则辅音模式将与“v”匹配并且它们将全部更改为“c”。所以必须先替换辅音。

Function wordClass(word As String) As String
    Dim Consonants As Object
    Set Consonants = CreateObject("VBScript.RegExp")
    With Consonants
        .Global = True
        .MultiLine = False
        .Pattern = "[bcdfghjklmnpqrstvwxz]|^y"
    End With
    
    Dim Vowels As Object
    Set Vowels = CreateObject("VBScript.RegExp")
    With Vowels
        .Global = True
        .MultiLine = False
        .Pattern = "[aeiouy]"
    End With
    
    Dim outputString As String
    outputString = LCase(word)
    
    outputString = Consonants.Replace(outputString, "c")
    outputString = Vowels.Replace(outputString, "v")
    wordClass = outputString
End Function

好吧,这是另一个答案。这次字母和它们的类型用于在字典模式下填充集合,因此我们可以在扫描单词时简化代码。因此我们只需要处理 y 作为第一个字母的特殊情况。


Private Type State

    LetterType                      As Collection

End Type

Private s                           As State

Public Sub TestWordClass()

    Debug.Print "The word class of Yucky is cvccv: Found is "; WordClass("Yucky")

End Sub


Public Function WordClass(ByVal ipWord As String) As String

    Dim myResult As String
    Dim myFirstLetter As String

    If s.LetterType Is Nothing Then SetupLetterTypes

    myFirstLetter = VBA.LCase$(VBA.Left$(ipWord, 1))
    If myFirstLetter = "y" Then
        
        myResult = "c"

    Else

        myResult = s.LetterType(myFirstLetter)

    End If


    Dim myIndex As Long
    For myIndex = 2 To VBA.Len(ipWord)

        Dim myLetter As String
        myLetter = VBA.LCase$(VBA.Mid$(ipWord, myIndex, 1))
        myResult = myResult & s.LetterType(myLetter)

    Next

    WordClass = myResult

End Function

Private Sub SetupLetterTypes()

    Dim myLetters As Variant
    myLetters = _
        Array _
        ( _
            "aeiouybcdfghjklmnpqrstvwxz", _
            "vvvvvvcccccccccccccccccccc" _
        )
    Set s.LetterType = New Collection

    Dim myIndex As Long
    
    For myIndex = 1 To VBA.Len(myLetters(0))
        
        s.LetterType.Add Item:=VBA.Mid$(myLetters(1), myIndex, 1), Key:=VBA.Mid$(myLetters(0), myIndex, 1)
        
    Next

End Sub

通过数组匹配的替代方法

这种方法不是将每个字母与不同类型的数组相关联,而是通过 Match 一次获得元音的顺序位置,该数组针对元音数组(包括 y):

    vowelpos = Application.Match(s2Arr(LCase(word)), Array("y", "a", "e", "i", "o", "u"), 0)

因此每个数值对应一个元音,non-findings (Error 2042) 对应一个辅音(“起始 y”-例外情况在 b 节中考虑)。

Function cv(ByVal word As String) As String
'a) get position of vowel within vowels array {y.a.e.i.o.u}
    Dim vowelpos
    vowelpos = Application.Match(s2Arr(LCase(word)), Array("y", "a", "e", "i", "o", "u"), 0)
'b) consider starting "y" as consonant (i.e. not as vowel)
    If vowelpos(1) = 1 Then vowelpos(1) = "Starting Y"
'c) replace letters with their type abbreviation "v"owel|"c"onsonant
    Dim i As Long
    For i = 1 To UBound(vowelpos)
        vowelpos(i) = IIf(IsNumeric(vowelpos(i)), "v", "c")
    Next i
'd) return joined letter types
    cv = Join(vowelpos, vbNullString)
End Function

帮助函数s2Arr()

允许将字符串原子化为字母数组。

Function s2Arr(ByVal s As String) As Variant
'Purp: return array of all single characters in a string
'Idea: 
    s = StrConv(s, vbUnicode)
    s2Arr = Split(s, vbNullChar, Len(s) \ 2)
End Function