Version 0.6.0
- honour capital/mixed cases for ignore case - consolidate consecutive matches - database upgrade capability - case sensitivity option reversed - removed obsolete WIM handling - skip empty mapping - Deletion of mapping
This commit is contained in:
@@ -2,8 +2,9 @@
|
||||
local _G = _G
|
||||
local Grichelde = _G.Grichelde
|
||||
|
||||
local nilOrEmpty, ipairs, tContains, tFilter, tInsert, tConcat, find, sub, gsub, toLower, trim, length
|
||||
= Grichelde.functions.nilOrEmpty, Grichelde.functions.ipairs, Grichelde.functions.tContains, Grichelde.functions.tFilter, Grichelde.functions.tInsert, Grichelde.functions.tConcat, Grichelde.functions.find, Grichelde.functions.sub, Grichelde.functions.gsub, Grichelde.functions.toLower, Grichelde.functions.trim, Grichelde.functions.length
|
||||
local nilOrEmpty, ipairs, spairs, tContains, tFilter, tInsert, tConcat, find, sub, isUpper, isLower, toUpper, toLower, trim, length
|
||||
= Grichelde.functions.nilOrEmpty, Grichelde.functions.ipairs, Grichelde.functions.spairs, Grichelde.functions.tContains, Grichelde.functions.tFilter, Grichelde.functions.tInsert, Grichelde.functions.tConcat,
|
||||
Grichelde.functions.find, Grichelde.functions.sub, Grichelde.functions.isUpper, Grichelde.functions.isLower, Grichelde.functions.toUpper, Grichelde.functions.toLower, Grichelde.functions.trim, Grichelde.functions.length
|
||||
|
||||
--- Before a chat message is sent, check if replacement is required and replace the text accordingly.
|
||||
-- @param message string
|
||||
@@ -13,7 +14,6 @@ local nilOrEmpty, ipairs, tContains, tFilter, tInsert, tConcat, find, sub, gsub,
|
||||
function Grichelde:SendChatMessage(message, type, language, channel, ...)
|
||||
local replacedText = self:CheckAndReplace(message, type)
|
||||
|
||||
self:DebugPrint("SendChatMessage : replacedText:", replacedText)
|
||||
|
||||
-- Send text in chunks if length exceeds 255 bytes after replacement
|
||||
local chunks = self:SplitText(replacedText)
|
||||
@@ -55,7 +55,7 @@ function Grichelde:CheckReplacement(text, channel)
|
||||
)
|
||||
self:DebugPrint("CheckReplacement : allowed channels:", tConcat(allowedChannels, ", "))
|
||||
local type = self:ConvertBlizChannelToType(channel)
|
||||
if (type ~= nil and not tContains(allowedChannels, type)) then
|
||||
if (type == nil or not tContains(allowedChannels, type)) then
|
||||
self:DebugPrint("CheckReplacement : skip channel type:", type)
|
||||
return false
|
||||
end
|
||||
@@ -103,7 +103,7 @@ function Grichelde:ReplaceText(text)
|
||||
|
||||
while current <= length(newText) do
|
||||
local currentChar = sub(newText, current, current)
|
||||
self:DebugPrint("current/char : %s,%s", current, currentChar)
|
||||
self:TracePrint("current/char : %s,%s", current, currentChar)
|
||||
|
||||
if ( not tContains(lookAheads, currentChar)) then
|
||||
current = current + 1
|
||||
@@ -194,17 +194,181 @@ end
|
||||
-- @param text string
|
||||
-- @return string
|
||||
function Grichelde:ReplaceCharacters(text)
|
||||
-- todo: read from options
|
||||
-- todo: case (in)sensitivity
|
||||
-- todo: consolidate consecutive
|
||||
-- todo: prevent infinite loops - is that even possible?
|
||||
local replacement = text
|
||||
replacement = gsub(replacement, "s", "ch")
|
||||
replacement = gsub(replacement, "S", "Ch")
|
||||
replacement = gsub(replacement, "t", "k")
|
||||
replacement = gsub(replacement, "T", "K")
|
||||
self:DebugPrint("ReplaceCharacters : replaced \"%s\" with \"%s\"", text, replacement)
|
||||
return replacement
|
||||
local replacements = self.db.profile.replacements or {}
|
||||
self:DebugPrint("ReplaceCharacters : replacements")
|
||||
self:DebugPrint(replacements)
|
||||
|
||||
local result = text
|
||||
local consolidate = {}
|
||||
|
||||
-- replacements are done first
|
||||
for replName, replTable in spairs(replacements) do
|
||||
local before = result
|
||||
local search = replTable.searchText
|
||||
|
||||
if not nilOrEmpty(search) then
|
||||
local replace = replTable.replaceText
|
||||
consolidate[replName] = {}
|
||||
|
||||
if replTable.ignoreCase then
|
||||
self:DebugPrint("ReplaceCharacters : \"%s => %s\" (ignoreCase)", search, replace)
|
||||
local pos, offset = 1, 0
|
||||
local lowerResult = toLower(result)
|
||||
local lowerSearch = toLower(search)
|
||||
|
||||
local pos1, pos2 = find(lowerResult, lowerSearch, pos)
|
||||
while (pos1 and pos2) do
|
||||
self:TracePrint("pos1: %d, pos2: %d", pos1, pos2)
|
||||
local pre = sub(result, 1, pos1 - 1 + offset)
|
||||
local match = sub(result, pos1 + offset, pos2 + offset)
|
||||
local post = sub(result, pos2 + 1 + offset)
|
||||
self:TracePrint("pre: %s, match: %s, post: %s", pre, match, post)
|
||||
|
||||
-- keep cases
|
||||
local repl = ""
|
||||
local lastCase = nil
|
||||
for p = pos1, pos2 do
|
||||
self:TracePrint("p: %d", p)
|
||||
local c = sub(match, p - pos1 + 1, p - pos1 + 1)
|
||||
local r = sub(replace, p - pos1 + 1, p - pos1 + 1) or ""
|
||||
|
||||
if (isUpper(c)) then -- all UPPER-CASE letter
|
||||
lastCase = true
|
||||
repl = repl .. toUpper(r)
|
||||
elseif (isLower(match)) then -- all lower_case letter
|
||||
lastCase = false
|
||||
repl = repl .. toLower(r)
|
||||
else -- no letter
|
||||
lastCase = nil
|
||||
repl = repl .. r
|
||||
end
|
||||
self:TracePrint("character: %s, %s", c, r)
|
||||
end
|
||||
|
||||
self:TracePrint("length %d > %d", length(replace), pos2 - pos1 + 1)
|
||||
if (length(replace) > pos2 - pos1 + 1) then
|
||||
local remainingReplace = sub(replace, pos2 - pos1 + 2)
|
||||
local nextLetter = sub(post, 1, 1)
|
||||
|
||||
self:TracePrint("rest: %s, n: %s, lastCase: %s", remainingReplace, nextLetter, lastCase)
|
||||
|
||||
if (isUpper(nextLetter)) then
|
||||
repl = repl .. toUpper(remainingReplace)
|
||||
elseif (isLower(nextLetter)) then
|
||||
repl = repl .. toLower(remainingReplace)
|
||||
else
|
||||
-- no letter
|
||||
repl = repl .. remainingReplace
|
||||
-- if lastCase == nil then
|
||||
-- repl = repl .. remainingReplace
|
||||
-- elseif lastCase == false then
|
||||
-- repl = repl .. toLower(remainingReplace)
|
||||
-- else
|
||||
-- repl = repl .. toUpper(remainingReplace)
|
||||
-- end
|
||||
end
|
||||
end
|
||||
|
||||
-- actual replacement
|
||||
result = pre .. repl .. post
|
||||
self:DebugPrint("result: %s", result)
|
||||
|
||||
-- remember positions for consolidate
|
||||
if replTable.consolidate then
|
||||
tInsert(consolidate[replName], pos1 + offset)
|
||||
end
|
||||
|
||||
-- replacement text can be longer or shorter the resulting text
|
||||
-- after replacement result and lowerResult can have different sizes
|
||||
offset = offset + length(repl) - length(lowerSearch)
|
||||
-- update values for next iteration
|
||||
pos = pos2 + 1
|
||||
pos1, pos2 = find(lowerResult, lowerSearch, pos)
|
||||
end
|
||||
else
|
||||
-- exact case
|
||||
self:DebugPrint("ReplaceCharacters : \"%s => %s\" (exact case)", search, replace)
|
||||
local pos, offset = 1, 0
|
||||
local oldResult = result
|
||||
|
||||
local pos1, pos2 = find(oldResult, search, pos)
|
||||
while (pos1 and pos2) do
|
||||
self:TracePrint("pos1: %d, pos2: %d", pos1, pos2)
|
||||
local pre = sub(result, 1, pos1 - 1 + offset)
|
||||
local post = sub(result, pos2 + 1 + offset)
|
||||
self:TracePrint("pre: %s, post: %s", pre, post)
|
||||
|
||||
-- actual replacement
|
||||
result = pre .. replace .. post
|
||||
self:DebugPrint("result: %s", result)
|
||||
|
||||
-- remember positions for consolidate
|
||||
if replTable.consolidate then
|
||||
tInsert(consolidate[replName], pos1 + offset)
|
||||
end
|
||||
|
||||
-- replacement text can lengthen or shorten the resulting text
|
||||
-- after replacement result and lowerResult can have different sizes
|
||||
offset = offset + length(replace) - length(search)
|
||||
-- update values for next iteration
|
||||
pos = pos2 + 1
|
||||
pos1, pos2 = find(oldResult, search, pos)
|
||||
end
|
||||
end
|
||||
|
||||
if before ~= result then
|
||||
self:DebugPrint("ReplaceCharacters : replaced \"%s\" with \"%s\"", before, result)
|
||||
end
|
||||
else
|
||||
self:DebugPrint("ReplaceCharacters : Skip replacement for empty mapping")
|
||||
end
|
||||
end
|
||||
|
||||
-- consolidation is done last
|
||||
for replName, replTable in spairs(replacements) do
|
||||
local before = result
|
||||
--local search = replTable.searchText
|
||||
local search = replTable.searchText
|
||||
|
||||
if not nilOrEmpty(search) then
|
||||
local replace = replTable.replaceText
|
||||
local lowerResult = toLower(result)
|
||||
local offset = 0
|
||||
|
||||
if replTable.consolidate then
|
||||
self:DebugPrint("ReplaceCharacters : consolidating \"%s => %s\"", search, replace)
|
||||
self:DebugPrint("consolidate[" .. replName .. "] is:")
|
||||
self:DebugPrint(consolidate[replName])
|
||||
|
||||
for _, pos1 in spairs(consolidate[replName]) do
|
||||
local pos2 = pos1 + length(replace) - 1
|
||||
self:TracePrint("pos1: %d, pos2: %d", pos1, pos2)
|
||||
local match = sub(lowerResult, pos1, pos2)
|
||||
local next = sub(lowerResult, pos2 + 1, pos2 + 1 + pos2 - pos1)
|
||||
self:TracePrint("match: %s, next: %s", match, next)
|
||||
|
||||
local _, p2 = find(next, "^" .. match)
|
||||
self:TracePrint("p2: %d", p2)
|
||||
if (p2) then
|
||||
result = sub(result, 1, pos2 + offset) .. sub(result, pos2 + 1 + p2 + offset)
|
||||
|
||||
-- consolidation will shorten the resulting text
|
||||
offset = offset + length(result) - length(lowerResult)
|
||||
end
|
||||
self:DebugPrint("result: %s", result)
|
||||
end
|
||||
end
|
||||
|
||||
if before ~= result then
|
||||
self:DebugPrint("ReplaceCharacters : consolidate \"%s\" with \"%s\"", before, result)
|
||||
end
|
||||
else
|
||||
self:DebugPrint("ReplaceCharacters : Skip consolidation for empty mapping")
|
||||
end
|
||||
end
|
||||
|
||||
self:DebugPrint("ReplaceCharacters : final text:", result)
|
||||
return result
|
||||
end
|
||||
|
||||
--- Splits a long text in longest possible chunks of <= 255 length, split at last available space
|
||||
|
||||
Reference in New Issue
Block a user