Here’s what I’ve wound up with. Not elegant but it seems to work for my needs. Someone may find it useful as a starting point.

```
function Speak ( Words, Speed )
if Speed == nil then
speech.rate = .4
else
speech.rate = Speed
end
Words = ReplaceString ( Words, "{/}", " divided by " ) -- Brackets are markup in text
Words = ReplaceString ( Words, "{!}", " apostrophe " )
Words = ReplaceString ( Words, "*", " times " )
Words = ReplaceString ( Words, "____", " fill in the blank " )
Words = FractionCheck ( Words )
speech.say ( Words )
end
function ReplaceString ( Words, Pattern, Replacement )
return ( Words:gsub ( Pattern, Replacement ) )
end
function FractionCheck ( Words ) -- Locate fractions and format for speech.
while true do -- Loop until end of Words
Numerator = nil
Denominator = nil
Start = string.find ( Words, "/", 1, true )
if Start ~= nil then -- Find numerator
NumeratorStart = 1
local IsNumber = true
while IsNumber == true do
Char = string.sub ( Words, Start-NumeratorStart, Start-NumeratorStart)
if Start-NumeratorStart > 0 and string.find ( "-0123456789", Char ) ~= nil then -- It's a number
NumeratorStart = NumeratorStart + 1
else
Numerator = string.sub ( Words, Start-NumeratorStart+1, Start-1 )
IsNumber = false
end
end
end
if Start ~= nil then -- Find denominator
DenominatorStart = 1
local IsNumber = true
while IsNumber == true do
Char = string.sub ( Words, Start + DenominatorStart, Start + DenominatorStart )
if Start + DenominatorStart < string.len ( Words ) and string.find ( "0123456789", Char ) ~= nil then -- It's a number
DenominatorStart = DenominatorStart + 1
else
Denominator = string.sub ( Words, Start + 1, Start + DenominatorStart-1 )
IsNumber = false
end
end
end
if Numerator ~= nil and Denominator ~= nil then -- It's a fraction
Numerator = Numerator
for Key, Value in pairs( Denominators ) do -- Lookup Denominator in table
if Denominators[Key][1] == Denominator then
if Numerator == "1" or Numerator == "-1" then -- Singular
Denominator = Denominators[Key][2]
else
Denominator = Denominators[Key][3]
end
end
end
Words = ( string.sub( Words, 1, Start - NumeratorStart ) .. Numerator .. " " .. Denominator .. string.sub ( Words, Start + DenominatorStart ) )
else
return ( Words )
end
end
end
function FractionsLoad()
Denominators = {}
Denominators[1] = {"1", " one ", " ones " }
Denominators[2] = {"2", " half ", " halves " }
Denominators[3] = {"3", " third ", " thirds " }
Denominators[4] = {"4", " fourth ", " fourths " }
Denominators[5] = {"5", " fifth ", " fifths " }
Denominators[6] = {"6", " sixth ", " sixths " }
Denominators[7] = {"7", " seventh ", " sevenths " }
Denominators[8] = {"8", " eight ", " eights " }
Denominators[9] = {"9", " ninth ", " ninths " }
Denominators[10] = {"10", " tenth ", " tenths " }
Denominators[11] = {"11", " eleventh ", " elevenths " }
Denominators[12] = {"12", " twelth ", " twelths " }
Denominators[13] = {"13", " thirteenth ", " thirteenths " }
Denominators[14] = {"15", " fifteenth ", " fifteenths " }
Denominators[15] = {"16", " sixteenth ", " sixteenth " }
Denominators[16] = {"17", " seventeenth ", " seventeenths " }
Denominators[17] = {"18", " eighteenth ", " eighteenths " }
Denominators[18] = {"19", " nineteehth ", " nineteenths " }
Denominators[20] = {"20", " twentieth ", " twentieths " }
Denominators[21] = {"21", " twenty first ", " twenty firsts " }
Denominators[22] = {"22", " twenty second ", " twenty seconds " }
Denominators[23] = {"23", " twenty third ", " twenty thirds " }
Denominators[24] = {"24", " twenty fourth ", " twenty fourths " }
Denominators[25] = {"32", " thirty second ", " thirty seconds " }
Denominators[26] = {"50", " fiftieth ", " fiftieths " }
Denominators[28] = {"64", " sixthy fourth ", " sixty fourths " }
Denominators[29] = {"100", " hundredth ", " hundredths " }
Denominators[30] = {"1000", " one thousandth ", " one thousandths " }
return
end
```