summaryrefslogtreecommitdiff
path: root/script/core/matchkey.lua
blob: 3c6a54a83ccc4ca741f30cb7f5f9d2f3aa3c0501 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
local lowers = {}
local uppers = {}
for c in ('abcdefghijklmnopqrstuvwxyz'):gmatch '.' do
    lowers[c] = true
    uppers[c:upper()] = true
end

---@param input string
---@param other string
local function isValidFirstChar(input, other)
    local first = input:sub(1, 1):upper()
    if first == other:sub(1, 1):upper() then
        return true
    end
    local pos = other:find(first, 2, true)
    if not pos and uppers[first] then
        -- word after symbol?
        if other:find('%A' .. first:lower(), 2) then
            return true
        end
    end
    if not pos then
        return false
    end
    local char = other:sub(pos, pos)
    -- symbol?
    if not uppers[char] then
        return true
    end
    -- word boundary?
    local beforeChar = other:sub(pos - 1, pos - 1)
    if not uppers[beforeChar] then
        return true
    end
    return false
end

local function isAlmostSame(input, other)
    local lMe = input:lower()
    local lOther = other:lower()
    if lMe == lOther:sub(1, #lMe) then
        return true
    end
    local chars = {}
    for i = 1, #lOther do
        local c = lOther:sub(i, i)
        chars[c] = (chars[c] or 0) + 1
    end
    for i = 1, #lMe do
        local c = lMe:sub(i, i)
        if chars[c] and chars[c] > 0 then
            chars[c] = chars[c] - 1
        else
            return false
        end
    end
    return true
end

---@param input string
---@param other string
---@param fast  boolean
---@return boolean isMatch
---@return number  deviation
return function (input, other, fast)
    if input == other then
        return true, 0
    end
    if input == '' then
        return true, 0
    end
    if #input > #other then
        return false, 0
    end
    if fast and input:sub(1, 1) ~= other:sub(1, 1) then
        return false, 0
    end
    if not isValidFirstChar(input, other) then
        return false, 0
    end
    if not isAlmostSame(input, other) then
        return false, 0
    end
    return true, 1
end