Given a word, I need a function that returns the structure of the word in terms of vowels and consonants. "c" stands for consonants and "v" for vowels. If the letter "y" is the first letter of a word, it is a consonant, otherwise, it considered a vowel. For example, wordClass("dance") returns "cvccv" and wordClass("yucky") returns "cvccv".
I tried this but there is probably a more efficient way to do this:
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
CodePudding user response:
I would use something like this. Copy this to a fresh module:
Public strVowels As String
Public arrVowels() As String
Public Function wordClass(strWord As String) As String
Dim lngLetter As Long
setup
For lngLetter = 1 To Len(strWord)
If isVowel(Mid(strWord, lngLetter, 1)) Then
wordClass = wordClass & "V"
Else
wordClass = wordClass & "C"
End If
Next lngLetter
End Function
Public Sub setup()
strVowels = "a;e;i;o;u"
arrVowels = Split(strVowels, ";")
End Sub
Public Function isVowel(strLetter As String)
isVowel = Not IsError(Application.Match(LCase(strLetter), arrVowels, False))
End Function
CodePudding user response:
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
CodePudding user response:
I would not define arrays, just use Instr to check if a character is within the vowels. To check for consonants, I would check that the character is not a vowel and that it is between "b" and "z" - else it is some other character.
"Efficiency" for me is mainly a matter of readability - no matter which attempt you use, everything is done in memory and unless you want to analyze millions of words, there is no need to optimize for speed.
I also check for the first character. If it is a "y", i put hardcoded that it is a Consonant and start the loop with the 2nd character.
This is my attempt:
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
CodePudding user response:
You could do this in two steps with regex. Regex can search the string for individual letters and then replace all matching letters with "c" or "v". You would have 2 patterns and 2 replacements and then it would be done.
Pattern 1 : "[bcdfghjklmnpqrstvwxz]|^y"
: Matches any character in that list or a leading y.
Pattern 2 : "[aeiouy]"
: Matches any character in that list
Since pattern 1 is applied first, all the remaining y's can be safely assumed to be vowel. Also, since the first pattern changes all consonants to "c", they won't match pattern 2 and be double-transformed. If you were to run the Vowel regex first and change the letters to "v", the consonant pattern would match with "v" and they would all change to "c". So the consonant replacement must happen first.
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