I Tried Vibe Coding and You'll Never Guess What Happened Next
I've been playing around with vibe coding. It has been a fun, frustrating, constructive, and inefficient experience.
For anyone unfamiliar with the term, vibe coding refers to a non-expert (like me!) using AI to produce code based on vibes and vague instructions, without a full understanding of what is going on under the hood.
To start, I should mention my qualifications for doing any coding. I'm not a professional programmer, but I'm not a total novice either. I took 3 years of computer science in high school, where I learned Pascal and C++, and I've dabbled in C++ and Swift for fun and in HTML/JavaScript for my company's website. I have a Linux homelab full of random services. So, I'm nowhere near a professional level, but I'm also not completely clueless. Just mostly clueless.
So, what did I vibe code? Using Claude (paid for 1 month) and Gemini (free trial for 1 month), I set out to make some Word macros in Visual Basic that would be useful for my editing work. In particular, I made macros for the following:
1) Analyzing acronyms in a paper to assist the editor in determining if they are properly defined.
2) Analyzing parenthetical citations to see which ones are alphabetical and which ones are chronological to help the editor note inconsistencies. For example: (Smith et al., 1997; Ando, 2018; Jones & Johnson, 2022) vs. (Ando, 2018; Jones & Johnson, 2022; Smith et al., 1997).
3) Analyzing hyphenated, open, and closed forms of words (e.g., policy-maker, policy maker, and policymaker, respectively) to assist the editor in spotting inconsistencies.
I managed to get workable versions of all the macros above, and I think the final versions will be beneficial to me and my small team of editors. However, it took a fair bit of time, considerable patience, and lots of banging my head against the proverbial wall. And there are still huge caveats to what you can accomplish with vibe coding.
Disclaimer: Needless to say, there are some fundamental problems with AI. It is inefficient in terms of energy and water usage and it is largely based on questionable or obviously stolen training data. So I apologize in advance for dabbling in the moral muck that AI today. I'll excuse myself on the grounds that this is very smol scale, and I think it is worth seeing what the technology can do to inform thinking on whether a more ethical and efficient version is worth pursuing. Also, I just like to play with new tech. Sorry.
So how was my experience with vibe coding? It was one part "wow!" when I got something that just "magically" worked and many parts "ugggggggg!" when I ran into the wall of stupid that is AI.
First, I'll show you what worked. Below is an example of the hyphewithnation checker's output (macro code provided at the end of the post). Here, you can see the color-coded output, which includes frequency counts and a listing of forms used. As an editor, I find this output to be really helpful for identifying errors that would be easily overlooked. But I guess it's natural that I would find it useful since I told the AI exactly what I wanted. In this sense, I can see the vibe coding being useful for bespoke or idiosyncratic solutions to niche problems that likely won't be addressed in commercial software.

The code isn't perfect. You can see that it doesn't gracefully handle "state-of-the-art", but it does handle singulars and plurals (filter-feeder, filter-feeders), and it can also spot inconsistencies where no hyphen is involved (e.g., well being vs. wellbeing). Although I'm happy with the result, the process of vibe coding was a pain in the ass.
The AI was constantly introducing errors. It was pretty good at filling in the blank canvas in response to my initial prompt. But as soon as I start iterating and refining the code, the AI would start shitting itself. It would introduce duplicate variable declaration or introduce undefined functions. It would forget that you were doing Visual Basic for a Word macro and introduce functions that were only available in Excel. Claude struggled a lot at handing variable types correctly, so it would have For loops with the wrong type of control variable or the wrong variable type as an argument to a dictionary object. Correcting these errors often required user intervention, like reminding the AI what the goal was (a VBA Word Macro!!) or telling the AI which variables were declared multiple times.
Another problem is that relatively simple changes cause the AI to lose it's shit. For example, in the above output, you can see there is color gradation to reflect the frequency of usage. The color and then the color gradation were added after the macro was working as intended (but in black and white). Adding the color led to multiple rounds of the AI introducing errors, and then it happened again when the color gradation was added. Maybe I am just a bad prompt engineer, but as the code became more complex, it seemed like any tweak was liable to send the AI into an error spiral.
Sometimes, I encountered errors that an AI was totally unable to fix. For example, Claude could not resolve an error that came up about an End If without an If block. Ultimately, I ended up sticking the code into Gemini, which recognized the error and fixed it.
Although I am not expert enough to say what is reasonable, I feel like the AI-generated code is overly long and overly complex. This is just my vibes now, but I feel like 1000 lines lines of code and almost 100 globally (?) declared variables is a bit excessive. People who talk about AI opening the door for non-coders to make apps and web pages are fucking insane. It is one thing to make an overly complex script that I don't fully understand to run locally on my machine to do a helpful task. But it would be madness to let me, a non-programmer, use AI to make code to run on a public, internet-facing server where users' data would have to be handled securely.
When the code starts getting long, another annoying thing is that either you have to waste time and usage credits to output the full code, or you have to start mucking about in the code yourself based on instructions from the AI about how change the code in multiple different places. This seems like an inherent flaw of current AI. It still uses lots of AI effort to do something trivial like spit out 1000 lines of mostly unchanged code
To sum up, I think my dabbling suggests that AI is still severely limited without a programmer who knows what they're doing. Maybe the future will be expert programmers assisted by AI, but with the current technology, I doubt it will be wannabe tech bros who know jack shit about programming but rely on AI.
I had fun and got some useful scripts out of this experience, but it was not efficient in terms of time. Prompt engineering is less a clever way of doing things and more a way of brute forcing your way to a tolerable solution. If you plan to do a lot of coding, it still seems worthwhile to actually learn to code. The upfront investment in learning will surely be better than being stuck with the inefficiencies and low-quality that come with being completely reliant on the AI.
Attribute VB_Name = "Hyphenation"
Option Explicit
' I'm making this available CC-BY-NC by Flock of Cats.
' Helper function to count occurrences of a word and collect examples
Function CountOccurrencesAndCollectExamples(doc As Document, wordToFind As String, ByVal examplesDict As Object) As Long
On Error GoTo ErrorHandler
Dim rng As Range
Dim count As Long
Dim maxIterations As Long
Dim iterations As Long
Dim foundText As String
' Create a duplicate of the document content to avoid modifying the original
Set rng = doc.Content.Duplicate
count = 0
' Set reasonable limits to prevent infinite loops
If doc.words.count > 1000 Then
maxIterations = doc.words.count
Else
maxIterations = 1000
End If
If maxIterations > 10000 Then
maxIterations = 10000 ' Cap at 10,000
End If
iterations = 0
With rng.Find
.ClearFormatting
.text = wordToFind
.Forward = True
.Wrap = wdFindStop ' Only search to the end, don't wrap around
.Format = False
.MatchWholeWord = True
.MatchCase = False
Do While .Execute
count = count + 1
iterations = iterations + 1
' Get the exact text as found in the document (preserves case)
foundText = rng.text
' Add the found text as an example
If Not examplesDict.Exists(foundText) Then
examplesDict.Add foundText, 1
Else
' Just increment the counter
examplesDict(foundText) = examplesDict(foundText) + 1
End If
If iterations > maxIterations Then Exit Do ' Emergency exit
' Move to the end of the current match
rng.Collapse wdCollapseEnd
' Check if we've reached the end of the document
If rng.Start >= doc.Content.End - 1 Then Exit Do
Loop
End With
' Clean up
Set rng = Nothing
CountOccurrencesAndCollectExamples = count
Exit Function
ErrorHandler:
CountOccurrencesAndCollectExamples = 0
End Function
' Helper function to check if a string contains only alphabetic characters
Function IsAlphaOnly(strText As String) As Boolean
Dim i As Integer
For i = 1 To Len(strText)
If Not (Mid(strText, i, 1) Like "[a-zA-Z]") Then
IsAlphaOnly = False
Exit Function
End If
Next i
IsAlphaOnly = True
End Function
' Helper function to format examples as a string
Function FormatExamplesString(examplesDict As Object) As String
On Error Resume Next
Dim result As String
Dim isFirst As Boolean
If examplesDict.count = 0 Then
FormatExamplesString = ""
Exit Function
End If
' Sort the examples alphabetically
Dim sortedKeys() As String
Dim i As Long, j As Long
Dim temp As String
Dim keyExample As Variant
' Create array with keys
ReDim sortedKeys(0 To examplesDict.count - 1)
i = 0
For Each keyExample In examplesDict.Keys
sortedKeys(i) = CStr(keyExample)
i = i + 1
Next
' Simple bubble sort
For i = 0 To UBound(sortedKeys) - 1
For j = i + 1 To UBound(sortedKeys)
If LCase(sortedKeys(i)) > LCase(sortedKeys(j)) Then
temp = sortedKeys(i)
sortedKeys(i) = sortedKeys(j)
sortedKeys(j) = temp
End If
Next j
Next i
result = "("
isFirst = True
' Build the examples string from sorted array
For i = 0 To UBound(sortedKeys)
If Not isFirst Then
result = result & ", "
Else
isFirst = False
End If
result = result & sortedKeys(i)
Next i
result = result & ")"
FormatExamplesString = result
End Function
Public Sub FindHyphenatedWords()
' Variable declarations
Dim doc As Document
Dim tempDoc As Document
Dim rngDoc As Range
Dim strText As String
Dim dictHyphenated As Object
Dim dictWords As Object
Dim maxIterations As Long
Dim iterations As Long
Dim parts As Variant
Dim strFirstPart As String
Dim strSecondPart As String
Dim baseHyphenForm As String
Dim baseOpenForm As String
Dim baseClosedForm As String
Dim wordForms As Variant
Dim baseWord As Variant
Dim originalSecondPart As String
Dim normalizedSecondPart As String
Dim varForm As String
Dim varType As String
Dim hyphenatedTotal As Long
Dim openTotal As Long
Dim closedTotal As Long
Dim tempCount As Long
Dim resultsDoc As Document
Dim tbl As Table
Dim rowCount As Integer
Dim tableRange As Range
Dim currentRow As Integer
Dim regEx As Object
Dim Matches As Object
Dim Match As Object
Dim variations As Object
Dim uniqueWordGroups As Object
Dim groupKey As Variant
Dim baseKey As Variant
Dim foundBase As Boolean
Dim wordGroup As Object
Dim standardBaseWord As String
Dim errorMsg As String
Dim totalHyphenated As Long
Dim totalOpen As Long
Dim totalClosed As Long
Dim forms(2) As String
Dim i As Integer
Dim dictFoundHyphenated As Object
Dim dictFoundOpen As Object
Dim dictFoundClosed As Object
Dim dictHyphenCount As Object
Dim dictOpenCount As Object
Dim dictClosedCount As Object
Dim hyphenColor As Long
Dim openColor As Long
Dim closedColor As Long
Dim rowTotal As Long
Dim hyphenPercent As Double
Dim openPercent As Double
Dim closedPercent As Double
Dim blueValue As Integer
Dim rbValue As Integer
Dim rgValue As Integer
Dim isFirstPartAlpha As Boolean
Dim isSecondPartAlpha As Boolean
Dim cellRange As Range
Dim hyphenExamplesText As String
Dim openExamplesText As String
Dim closedExamplesText As String
Dim exampleWord As Variant
Dim closedSecondPart As String
Dim standardForm As String
Dim variationKey As Variant
Dim variantKey As Variant
Dim potentialOpenForm As Variant
Dim potentialClosedForm As String
Dim potentialMatch As String
Dim dictOpenForms As Object
Dim dictClosedForms As Object
' Store initial application settings to restore them later
Dim initialScreenUpdating As Boolean
Dim initialStatusBar As Boolean
Dim initialCalculation As Long
initialScreenUpdating = Application.ScreenUpdating
initialStatusBar = Application.DisplayStatusBar
' Error handling
On Error GoTo ErrorHandler
' Set reference to the active document
If Documents.count = 0 Then
MsgBox "No document is open. Please open a document and try again.", vbExclamation
Exit Sub
End If
Set doc = ActiveDocument
' Check if document has content
If doc.Content.Characters.count <= 1 Then
MsgBox "Document is empty. Please add content and try again.", vbExclamation
Exit Sub
End If
' Performance optimizations
Application.ScreenUpdating = False
Application.DisplayStatusBar = True
Application.StatusBar = "Accepting all track changes... Please wait."
' Create a temporary document for analysis
Set tempDoc = Documents.Add(Visible:=False)
doc.Content.Copy
tempDoc.Content.Paste
' Accept all track changes in the temporary document
tempDoc.TrackRevisions = False
tempDoc.AcceptAllRevisions
' Set rngDoc to use the clean temporary document
Set rngDoc = tempDoc.Content
' Create dictionaries to store word forms and counts with optimized settings
Set dictHyphenated = CreateObject("Scripting.Dictionary")
dictHyphenated.CompareMode = vbTextCompare ' Case-insensitive
Set dictWords = CreateObject("Scripting.Dictionary")
dictWords.CompareMode = vbTextCompare
' Create dictionaries to track found words for examples
Set dictFoundHyphenated = CreateObject("Scripting.Dictionary")
Set dictFoundOpen = CreateObject("Scripting.Dictionary")
Set dictFoundClosed = CreateObject("Scripting.Dictionary")
' Create dictionaries for counts
Set dictHyphenCount = CreateObject("Scripting.Dictionary")
dictHyphenCount.CompareMode = vbTextCompare
Set dictOpenCount = CreateObject("Scripting.Dictionary")
dictOpenCount.CompareMode = vbTextCompare
Set dictClosedCount = CreateObject("Scripting.Dictionary")
dictClosedCount.CompareMode = vbTextCompare
' Set maximum iterations - scale with document size but with bounds
maxIterations = doc.words.count * 2
If maxIterations < 1000 Then
maxIterations = 1000 ' Minimum value
End If
If maxIterations > 100000 Then
maxIterations = 100000 ' Maximum value
End If
iterations = 0
' Show progress information
Application.StatusBar = "Finding hyphenated words... Please wait."
' Use regular expression to find hyphenated words
Set regEx = CreateObject("VBScript.RegExp")
regEx.Global = True
regEx.pattern = "\b[a-zA-Z]+-[a-zA-Z]+\b"
Set Matches = regEx.Execute(rngDoc.text)
' Process hyphenated words
For Each Match In Matches
iterations = iterations + 1
If iterations Mod 100 = 0 Then
Application.StatusBar = "Processing hyphenated words... " & iterations & " of " & Matches.count
DoEvents ' Allow UI to update
End If
If iterations > maxIterations Then
MsgBox "Maximum iterations reached. Analysis is incomplete. Try with a smaller document.", vbExclamation
Exit For
End If
strText = Match.Value
' Skip if already processed
If Not dictHyphenated.Exists(strText) Then
' Split the word into parts
parts = Split(strText, "-")
' Only process words with one hyphen
If UBound(parts) = 1 Then
strFirstPart = parts(0)
strSecondPart = parts(1)
' Only process words with meaningful parts (at least 2 characters each)
If Len(strFirstPart) >= 2 And Len(strSecondPart) >= 2 Then
' Store original second part before any transformations
originalSecondPart = strSecondPart
' Make a copy of the second part for normalization
normalizedSecondPart = strSecondPart
' Check for -ies ending (could be plural of -y)
If Len(normalizedSecondPart) >= 3 Then
If Right(normalizedSecondPart, 3) = "ies" Then
normalizedSecondPart = Left(normalizedSecondPart, Len(normalizedSecondPart) - 3) & "y"
' Check for regular plural with 's'
ElseIf Right(normalizedSecondPart, 1) = "s" Then
normalizedSecondPart = Left(normalizedSecondPart, Len(normalizedSecondPart) - 1)
End If
End If
' Use normalized version for base form detection
strSecondPart = normalizedSecondPart
' Check if both parts contain only alphabetic characters
isFirstPartAlpha = IsAlphaOnly(strFirstPart)
isSecondPartAlpha = IsAlphaOnly(strSecondPart)
If Len(strFirstPart) > 0 And Len(strSecondPart) > 0 And _
isFirstPartAlpha And isSecondPartAlpha Then
' Create the normalized form for the base word
If Right(strSecondPart, 1) = "y" And originalSecondPart <> strSecondPart Then
' We've converted "ies" to "y" - use this as the base form
baseHyphenForm = LCase(strFirstPart) & "-" & LCase(strSecondPart)
Else
' Use the normalized singular form
baseHyphenForm = LCase(strFirstPart) & "-" & LCase(strSecondPart)
End If
' Check if we already have this base form (case-insensitive)
foundBase = False
For Each baseKey In dictWords.Keys
If LCase(baseKey) = baseHyphenForm Then
foundBase = True
baseHyphenForm = baseKey
Exit For
End If
Next baseKey
' Add to dictionary with original form linked to base form
If Not dictHyphenated.Exists(strText) Then
dictHyphenated.Add strText, baseHyphenForm
End If
' Setup word forms dictionary
If Not dictWords.Exists(baseHyphenForm) Then
' Create an array to store base variations
' 0: hyphenated, 1: open, 2: closed
forms(0) = baseHyphenForm
forms(1) = LCase(strFirstPart) & " " & LCase(strSecondPart)
forms(2) = LCase(strFirstPart) & LCase(strSecondPart)
dictWords.Add baseHyphenForm, forms
' Initialize dictionaries for found examples
Set dictFoundHyphenated(baseHyphenForm) = CreateObject("Scripting.Dictionary")
Set dictFoundOpen(baseHyphenForm) = CreateObject("Scripting.Dictionary")
Set dictFoundClosed(baseHyphenForm) = CreateObject("Scripting.Dictionary")
End If
' Add the original found form as an example for its base form
If Not dictFoundHyphenated(baseHyphenForm).Exists(strText) Then
dictFoundHyphenated(baseHyphenForm).Add strText, 1
Else
dictFoundHyphenated(baseHyphenForm)(strText) = dictFoundHyphenated(baseHyphenForm)(strText) + 1
End If
End If
End If
End If
End If
Next Match
' NEW FEATURE: Look for open/closed pairs ======================================
' Check if we want to continue searching for open/closed form pairs
Application.StatusBar = "Looking for open/closed word pairs..."
' Create a dictionary to store potential open forms
Set dictOpenForms = CreateObject("Scripting.Dictionary")
dictOpenForms.CompareMode = vbTextCompare
' Create a dictionary to store potential closed forms
Set dictClosedForms = CreateObject("Scripting.Dictionary")
dictClosedForms.CompareMode = vbTextCompare
' Find all open forms (two words together)
regEx.pattern = "\b[a-zA-Z]{2,}[ ][a-zA-Z]{2,}\b"
Set Matches = regEx.Execute(rngDoc.text)
For Each Match In Matches
potentialOpenForm = Match.Value
If Not dictOpenForms.Exists(potentialOpenForm) Then
dictOpenForms.Add potentialOpenForm, 1
End If
Next Match
' Find all potentially relevant closed forms
regEx.pattern = "\b[a-zA-Z]{4,}\b"
Set Matches = regEx.Execute(rngDoc.text)
For Each Match In Matches
potentialClosedForm = Match.Value
' Only track if 4+ characters (to be a potential compound)
If Len(potentialClosedForm) >= 4 Then
If Not dictClosedForms.Exists(potentialClosedForm) Then
dictClosedForms.Add potentialClosedForm, 1
End If
End If
Next Match
' Now look for matching pairs
Application.StatusBar = "Analyzing potential compound word pairs..."
For Each potentialOpenForm In dictOpenForms.Keys
' Split the open form into two parts
parts = Split(potentialOpenForm, " ")
' Only proceed if exactly two parts
If UBound(parts) = 1 Then
strFirstPart = parts(0)
strSecondPart = parts(1)
' Only process words with meaningful parts (at least 2 characters each)
If Len(strFirstPart) >= 2 And Len(strSecondPart) >= 2 Then
' Check if both parts contain only alphabetic characters
isFirstPartAlpha = IsAlphaOnly(strFirstPart)
isSecondPartAlpha = IsAlphaOnly(strSecondPart)
If isFirstPartAlpha And isSecondPartAlpha Then
' Create the potential closed form
potentialMatch = LCase(strFirstPart) & LCase(strSecondPart)
' Check if this closed form exists in the document
If dictClosedForms.Exists(potentialMatch) Then
' We have both open and closed forms - create a new base entry if needed
baseHyphenForm = LCase(strFirstPart) & "-" & LCase(strSecondPart)
' Check if we already have this form from the hyphenated search
foundBase = False
For Each baseKey In dictWords.Keys
If LCase(baseKey) = baseHyphenForm Then
foundBase = True
baseHyphenForm = baseKey
Exit For
End If
Next baseKey
If Not foundBase Then
' This is a new compound term not previously found via hyphenation
' Create an array to store base variations
forms(0) = baseHyphenForm
forms(1) = LCase(strFirstPart) & " " & LCase(strSecondPart)
forms(2) = LCase(strFirstPart) & LCase(strSecondPart)
dictWords.Add baseHyphenForm, forms
' Initialize dictionaries for found examples
Set dictFoundHyphenated(baseHyphenForm) = CreateObject("Scripting.Dictionary")
Set dictFoundOpen(baseHyphenForm) = CreateObject("Scripting.Dictionary")
Set dictFoundClosed(baseHyphenForm) = CreateObject("Scripting.Dictionary")
' Add the open form as an example
If Not dictFoundOpen(baseHyphenForm).Exists(potentialOpenForm) Then
dictFoundOpen(baseHyphenForm).Add potentialOpenForm, 1
End If
' Add the closed form as an example
If Not dictFoundClosed(baseHyphenForm).Exists(potentialMatch) Then
dictFoundClosed(baseHyphenForm).Add potentialMatch, 1
End If
End If
End If
End If
End If
End If
Next
' Check if we found any valid words (either hyphenated or open/closed pairs)
If dictWords.count = 0 Then
Application.StatusBar = False
Application.ScreenUpdating = True
MsgBox "No valid hyphenated words or matching open/closed word pairs were found in this document.", vbInformation
GoTo CleanupAndExit
End If
' Second phase: Count all variations of each normalized word
Application.StatusBar = "Counting word variations..."
' Reset iterations counter
iterations = 0
' Process each base word
For Each baseWord In dictWords.Keys
iterations = iterations + 1
If iterations Mod 10 = 0 Then
Application.StatusBar = "Analyzing word variations... " & iterations & " of " & dictWords.count
DoEvents ' Allow UI to update
End If
' Extract parts from the base word (which is in hyphenated form)
parts = Split(baseWord, "-")
strFirstPart = parts(0)
strSecondPart = parts(1)
' Get all three forms of this word
wordForms = dictWords.item(baseWord)
baseHyphenForm = wordForms(0) ' my-number
baseOpenForm = wordForms(1) ' my number
baseClosedForm = wordForms(2) ' mynumber
' Create all possible variations for this base form
Set variations = CreateObject("Scripting.Dictionary")
' === HYPHENATED FORMS ===
' Add the singular form
variations.Add baseHyphenForm, "hyphen"
' Add plural forms based on word ending
If Right(strSecondPart, 1) = "y" Then
' -y to -ies plural transformation
variations.Add strFirstPart & "-" & Left(strSecondPart, Len(strSecondPart) - 1) & "ies", "hyphen"
' If we also have a "ey" form, add its plural too
If Right(strSecondPart, 2) = "ey" Then
variations.Add strFirstPart & "-" & Left(strSecondPart, Len(strSecondPart) - 1) & "eies", "hyphen"
End If
ElseIf Right(strSecondPart, 1) = "s" Or Right(strSecondPart, 1) = "x" Or Right(strSecondPart, 1) = "z" Or _
Right(strSecondPart, 2) = "sh" Or Right(strSecondPart, 2) = "ch" Then
' Words ending in s, x, z, sh, ch add -es
variations.Add baseHyphenForm & "es", "hyphen"
End If
' Regular plural with s
variations.Add baseHyphenForm & "s", "hyphen"
' Always add -es form for cases like "numberes"
If Not variations.Exists(baseHyphenForm & "es") Then
variations.Add baseHyphenForm & "es", "hyphen"
End If
' === OPEN FORMS ===
' Add the singular form
variations.Add baseOpenForm, "open"
' Add plural forms based on word ending
If Right(strSecondPart, 1) = "y" Then
' -y to -ies plural transformation
variations.Add strFirstPart & " " & Left(strSecondPart, Len(strSecondPart) - 1) & "ies", "open"
' If we also have a "ey" form, add its plural too
If Right(strSecondPart, 2) = "ey" Then
variations.Add strFirstPart & " " & Left(strSecondPart, Len(strSecondPart) - 1) & "eies", "open"
End If
ElseIf Right(strSecondPart, 1) = "s" Or Right(strSecondPart, 1) = "x" Or Right(strSecondPart, 1) = "z" Or _
Right(strSecondPart, 2) = "sh" Or Right(strSecondPart, 2) = "ch" Then
' Words ending in s, x, z, sh, ch add -es
variations.Add baseOpenForm & "es", "open"
End If
' Regular plural with s
variations.Add baseOpenForm & "s", "open"
' Always add -es form for cases like "numberes"
If Not variations.Exists(baseOpenForm & "es") Then
variations.Add baseOpenForm & "es", "open"
End If
' === CLOSED FORMS ===
' Add the singular form
variations.Add baseClosedForm, "closed"
' Add plural forms based on the ending of the closed form
closedSecondPart = Mid(baseClosedForm, Len(strFirstPart) + 1)
If Right(closedSecondPart, 1) = "y" Then
' -y to -ies plural transformation for closed form
variations.Add strFirstPart & Left(closedSecondPart, Len(closedSecondPart) - 1) & "ies", "closed"
ElseIf Right(closedSecondPart, 1) = "s" Or Right(closedSecondPart, 1) = "x" Or Right(closedSecondPart, 1) = "z" Or _
Right(closedSecondPart, 2) = "sh" Or Right(closedSecondPart, 2) = "ch" Then
' Words ending in s, x, z, sh, ch add -es
variations.Add baseClosedForm & "es", "closed"
End If
' Regular plural with s
variations.Add baseClosedForm & "s", "closed"
' Always add -es form for cases like "numberes"
If Not variations.Exists(baseClosedForm & "es") Then
variations.Add baseClosedForm & "es", "closed"
End If
' Now count all variations in the document
hyphenatedTotal = 0
openTotal = 0
closedTotal = 0
' Loop through all variations
For Each variationKey In variations.Keys
varForm = variationKey
varType = variations(variationKey)
Select Case varType
Case "hyphen"
' It's a hyphenated form
tempCount = CountOccurrencesAndCollectExamples(tempDoc, CStr(varForm), dictFoundHyphenated(baseWord))
hyphenatedTotal = hyphenatedTotal + tempCount
Case "open"
' It's an open form
tempCount = CountOccurrencesAndCollectExamples(tempDoc, CStr(varForm), dictFoundOpen(baseWord))
openTotal = openTotal + tempCount
Case "closed"
' It's a closed form
tempCount = CountOccurrencesAndCollectExamples(tempDoc, CStr(varForm), dictFoundClosed(baseWord))
closedTotal = closedTotal + tempCount
End Select
Next variationKey
' Store the counts in dictionaries
dictHyphenCount.Add baseWord, hyphenatedTotal
dictOpenCount.Add baseWord, openTotal
dictClosedCount.Add baseWord, closedTotal
Next baseWord
' Before creating the table, coalesce words that should be considered the same
Application.StatusBar = "Normalizing word forms..."
Set wordGroup = CreateObject("Scripting.Dictionary")
' First pass - identify standard forms (e.g., number vs numbey)
For Each baseWord In dictWords.Keys
parts = Split(baseWord, "-")
' Special handling for "numbey" vs "number" type words
If Len(parts(1)) >= 4 Then
' Check if the word ends with "ey"
If Right(LCase(parts(1)), 2) = "ey" Then
' Generate potential standard form with "er" ending
standardForm = LCase(parts(0)) & "-" & Left(LCase(parts(1)), Len(parts(1)) - 2) & "er"
' See if we have this standard form
For Each baseKey In dictWords.Keys
If LCase(baseKey) = standardForm Then
' Found standard form - map this "ey" word to standard
wordGroup.Add baseWord, baseKey
Exit For
End If
Next baseKey
End If
' Handle potential "ies/y" situations
If Right(LCase(parts(1)), 3) = "ies" Then
' Generate potential standard form with "y" ending
standardForm = LCase(parts(0)) & "-" & Left(LCase(parts(1)), Len(parts(1)) - 3) & "y"
' See if we have this standard form
For Each baseKey In dictWords.Keys
If LCase(baseKey) = standardForm Then
' Map plural to singular
wordGroup.Add baseWord, baseKey
Exit For
End If
Next baseKey
' Also check for possible "eies" to "ey" mapping
If Len(parts(1)) > 4 And Left(Right(LCase(parts(1)), 4), 1) = "e" Then
standardForm = LCase(parts(0)) & "-" & Left(LCase(parts(1)), Len(parts(1)) - 4) & "ey"
For Each baseKey In dictWords.Keys
If LCase(baseKey) = standardForm Then
' Map this "eies" form to "ey" form
wordGroup.Add baseWord, baseKey
Exit For
End If
Next baseKey
End If
End If
End If
Next baseWord
Application.StatusBar = "Creating results table..."
' Now reset the uniqueWordGroups collection for table generation
Set uniqueWordGroups = CreateObject("Scripting.Dictionary")
' Add all words to groups, using the standard form when available
For Each baseWord In dictWords.Keys
If wordGroup.Exists(baseWord) Then
' This is a non-standard word (e.g., "numbey") - use its standard form
standardBaseWord = wordGroup(baseWord)
If Not uniqueWordGroups.Exists(LCase(standardBaseWord)) Then
uniqueWordGroups.Add LCase(standardBaseWord), standardBaseWord
End If
Else
' This is either a standard word or one without a variant
If Not uniqueWordGroups.Exists(LCase(baseWord)) Then
uniqueWordGroups.Add LCase(baseWord), baseWord
End If
End If
Next baseWord
' Create results document
Set resultsDoc = Documents.Add
' Add a header
With resultsDoc.Content
.text = "Hyphenated Words Analysis" & vbCrLf & vbCrLf
.ParagraphFormat.Alignment = wdAlignParagraphCenter
.Font.Bold = True
.Font.Size = 14
.InsertParagraphAfter
End With
' Add document info
With resultsDoc.Content
.Collapse wdCollapseEnd
.Font.Bold = False
.Font.Size = 10
.text = "Source document: " & doc.name & vbCrLf
.text = "Analysis date: " & Format(Now, "yyyy-mm-dd hh:mm:ss") & vbCrLf
.text = "Number of unique hyphenated word groups: " & uniqueWordGroups.count & vbCrLf & vbCrLf
End With
' Reset formatting
With resultsDoc.Content
.Collapse wdCollapseEnd
.Font.Size = 11
.ParagraphFormat.Alignment = wdAlignParagraphLeft
End With
' Create a table for results
rowCount = uniqueWordGroups.count + 1 ' +1 for header row
' Create table with 3 columns (Hyphenated, Open, Closed)
Set tableRange = resultsDoc.Range(resultsDoc.Content.End - 1, resultsDoc.Content.End - 1)
Set tbl = resultsDoc.Tables.Add(Range:=tableRange, NumRows:=rowCount, NumColumns:=3)
tbl.Borders.Enable = True
' Set table header
tbl.Cell(1, 1).Range.text = "Hyphenated Form"
tbl.Cell(1, 2).Range.text = "Open Form"
tbl.Cell(1, 3).Range.text = "Closed Form"
' Format the header row
tbl.Rows(1).Range.Font.Bold = True
tbl.Rows(1).Shading.BackgroundPatternColor = wdColorGray15
' Make sure all rows except the header are not bold
For i = 2 To tbl.Rows.count
tbl.Rows(i).Range.Font.Bold = False
Next i
' Sort group keys alphabetically
Dim sortedKeys() As String
Dim tempKey As String
Dim k As Long, m As Long
' Create array with the unique word group keys
ReDim sortedKeys(0 To uniqueWordGroups.count - 1)
i = 0
For Each groupKey In uniqueWordGroups.Keys
sortedKeys(i) = CStr(groupKey)
i = i + 1
Next
' Simple bubble sort to alphabetize
For k = 0 To UBound(sortedKeys) - 1
For m = k + 1 To UBound(sortedKeys)
If LCase(sortedKeys(k)) > LCase(sortedKeys(m)) Then
tempKey = sortedKeys(k)
sortedKeys(k) = sortedKeys(m)
sortedKeys(m) = tempKey
End If
Next m
Next k
' Variable to track current row
currentRow = 2 ' Start after header row
' Track totals
totalHyphenated = 0
totalOpen = 0
totalClosed = 0
' Process each unique word group in alphabetical order
For i = 0 To UBound(sortedKeys)
groupKey = sortedKeys(i)
baseWord = uniqueWordGroups(groupKey)
On Error Resume Next ' Add error handling for this section
' Get the canonical base word for this group
baseWord = uniqueWordGroups(groupKey)
' Make sure the dictionaries exist for this base word
If Not dictFoundHyphenated.Exists(baseWord) Then
Set dictFoundHyphenated(baseWord) = CreateObject("Scripting.Dictionary")
End If
If Not dictFoundOpen.Exists(baseWord) Then
Set dictFoundOpen(baseWord) = CreateObject("Scripting.Dictionary")
End If
If Not dictFoundClosed.Exists(baseWord) Then
Set dictFoundClosed(baseWord) = CreateObject("Scripting.Dictionary")
End If
' Need to combine all counts for standard and variant forms
hyphenatedTotal = 0
openTotal = 0
closedTotal = 0
' For this word and all its variants, merge counts and examples
If dictHyphenCount.Exists(baseWord) Then
hyphenatedTotal = hyphenatedTotal + dictHyphenCount(baseWord)
End If
If dictOpenCount.Exists(baseWord) Then
openTotal = openTotal + dictOpenCount(baseWord)
End If
If dictClosedCount.Exists(baseWord) Then
closedTotal = closedTotal + dictClosedCount(baseWord)
End If
' Check for variant forms that need to be merged
For Each variantKey In wordGroup.Keys
If wordGroup(variantKey) = baseWord Then
' This variant maps to our base word
If dictHyphenCount.Exists(variantKey) Then
hyphenatedTotal = hyphenatedTotal + dictHyphenCount(variantKey)
End If
If dictOpenCount.Exists(variantKey) Then
openTotal = openTotal + dictOpenCount(variantKey)
End If
If dictClosedCount.Exists(variantKey) Then
closedTotal = closedTotal + dictClosedCount(variantKey)
End If
' Also merge the examples dictionaries
If dictFoundHyphenated.Exists(variantKey) Then
' For each example in the variant's dictionary, add it to the base word's dictionary if it's not already there
For Each exampleWord In dictFoundHyphenated(variantKey).Keys
If Not dictFoundHyphenated(baseWord).Exists(exampleWord) Then
dictFoundHyphenated(baseWord).Add exampleWord, dictFoundHyphenated(variantKey)(exampleWord)
End If
Next exampleWord
End If
If dictFoundOpen.Exists(variantKey) Then
For Each exampleWord In dictFoundOpen(variantKey).Keys
If Not dictFoundOpen(baseWord).Exists(exampleWord) Then
dictFoundOpen(baseWord).Add exampleWord, dictFoundOpen(variantKey)(exampleWord)
End If
Next exampleWord
End If
If dictFoundClosed.Exists(variantKey) Then
For Each exampleWord In dictFoundClosed(variantKey).Keys
If Not dictFoundClosed(baseWord).Exists(exampleWord) Then
dictFoundClosed(baseWord).Add exampleWord, dictFoundClosed(variantKey)(exampleWord)
End If
Next exampleWord
End If
End If
Next variantKey
On Error GoTo 0 ' Resume normal error handling
' Update totals
totalHyphenated = totalHyphenated + hyphenatedTotal
totalOpen = totalOpen + openTotal
totalClosed = totalClosed + closedTotal
' Get the word forms
If dictWords.Exists(baseWord) Then
wordForms = dictWords.item(baseWord)
baseHyphenForm = wordForms(0)
baseOpenForm = wordForms(1)
baseClosedForm = wordForms(2)
Else
' If forms don't exist, create them from the base word
parts = Split(baseWord, "-")
baseHyphenForm = baseWord
baseOpenForm = parts(0) & " " & parts(1)
baseClosedForm = parts(0) & parts(1)
End If
' Calculate row total for color intensity calculations
rowTotal = hyphenatedTotal + openTotal + closedTotal
If rowTotal > 0 Then
hyphenPercent = hyphenatedTotal / rowTotal
openPercent = openTotal / rowTotal
closedPercent = closedTotal / rowTotal
Else
hyphenPercent = 0
openPercent = 0
closedPercent = 0
End If
' Display in the table with color coding
If currentRow <= tbl.Rows.count Then
' Color intensity based on percentage (higher = darker)
blueValue = 128 + Int(127 * (1 - hyphenPercent))
If blueValue < 0 Then blueValue = 0
If blueValue > 255 Then blueValue = 255
hyphenColor = RGB(255, 255, blueValue)
' Hyphenated form - use a simpler approach to avoid "Not a valid action" errors
Set cellRange = tbl.Cell(currentRow, 1).Range
cellRange.text = baseHyphenForm & " (" & hyphenatedTotal & ")"
' Add examples if available - using a more compatible approach
If dictFoundHyphenated.Exists(baseWord) And dictFoundHyphenated(baseWord).count > 0 Then
hyphenExamplesText = FormatExamplesString(dictFoundHyphenated(baseWord))
If Len(hyphenExamplesText) > 0 Then
' Use this simpler approach that works across Word versions
cellRange.text = cellRange.text & hyphenExamplesText
End If
End If
' Set cell background color
tbl.Cell(currentRow, 1).Shading.BackgroundPatternColor = hyphenColor
' Format and display the open form - using compatible approach
rbValue = 128 + Int(127 * (1 - openPercent))
If rbValue < 0 Then rbValue = 0
If rbValue > 255 Then rbValue = 255
openColor = RGB(rbValue, rbValue, 255)
Set cellRange = tbl.Cell(currentRow, 2).Range
cellRange.text = baseOpenForm & " (" & openTotal & ")"
' Add examples if available - using compatible approach
If dictFoundOpen.Exists(baseWord) And dictFoundOpen(baseWord).count > 0 Then
openExamplesText = FormatExamplesString(dictFoundOpen(baseWord))
If Len(openExamplesText) > 0 Then
cellRange.text = cellRange.text & openExamplesText
End If
End If
' Set cell background color
tbl.Cell(currentRow, 2).Shading.BackgroundPatternColor = openColor
' Format and display the closed form - using compatible approach
rgValue = 128 + Int(127 * (1 - closedPercent))
If rgValue < 0 Then rgValue = 0
If rgValue > 255 Then rgValue = 255
closedColor = RGB(rgValue, 255, rgValue)
Set cellRange = tbl.Cell(currentRow, 3).Range
cellRange.text = baseClosedForm & " (" & closedTotal & ")"
' Add examples if available - using compatible approach
If dictFoundClosed.Exists(baseWord) And dictFoundClosed(baseWord).count > 0 Then
closedExamplesText = FormatExamplesString(dictFoundClosed(baseWord))
If Len(closedExamplesText) > 0 Then
cellRange.text = cellRange.text & closedExamplesText
End If
End If
' Set cell background color
tbl.Cell(currentRow, 3).Shading.BackgroundPatternColor = closedColor
' Move to next row
currentRow = currentRow + 1
End If
Next i ' Process next sorted key
' Format the table
tbl.AutoFitBehavior wdAutoFitContent
CleanupAndExit:
' Close the temporary document
On Error Resume Next
If Not tempDoc Is Nothing Then
tempDoc.Close wdDoNotSaveChanges
End If
On Error GoTo ErrorHandler
' Reset status bar and screen updating
Application.StatusBar = False
Application.ScreenUpdating = initialScreenUpdating
Application.DisplayStatusBar = initialStatusBar
' We've removed the stats summary and message box as requested
Exit Sub
ErrorHandler:
' Restore screen updating and status bar
Application.ScreenUpdating = initialScreenUpdating
Application.StatusBar = False
Application.DisplayStatusBar = initialStatusBar
' Close the temporary document if it exists
On Error Resume Next
If Not tempDoc Is Nothing Then
tempDoc.Close wdDoNotSaveChanges
End If
On Error GoTo 0
' Display error message
errorMsg = "An error occurred during analysis:" & vbCrLf & vbCrLf & _
"Error Number: " & err.Number & vbCrLf & _
"Description: " & err.Description
MsgBox errorMsg, vbCritical, "Error in FindHyphenatedWords"
End Sub