Files
rime_wanxiang/lua/number_translator.lua
2026-01-21 17:43:36 +08:00

176 lines
7.7 KiB
Lua
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
-- 来源 https://github.com/yanhuacuo/98wubi-tables > http://98wb.ysepan.com/
-- 数字、金额大写
-- 触发前缀默认为 recognizer/patterns/number 的第 2 个字符,即 R
local function splitNumPart(str)
local part = {}
part.int, part.dot, part.dec = string.match(str, "^(%d*)(%.?)(%d*)")
return part
end
local function GetPreciseDecimal(nNum, n)
if type(nNum) ~= "number" then nNum = tonumber(nNum) end
n = n or 0;
n = math.floor(n)
if n < 0 then n = 0 end
local nDecimal = 10 ^ n
local nTemp = math.floor(nNum * nDecimal);
local nRet = nTemp / nDecimal;
return nRet;
end
local function decimal_func(str, posMap, valMap)
local dec
posMap = posMap or { [1] = "", [2] = "", [3] = "", [4] = "" }
valMap = valMap or { [0] = "", "", "", "", "", "", "", "", "", "" }
if #str > 4 then dec = string.sub(tostring(str), 1, 4) else dec = tostring(str) end
dec = string.gsub(dec, "0+$", "")
if dec == "" then return "" end
local result = ""
for pos = 1, #dec do
local val = tonumber(string.sub(dec, pos, pos))
if val ~= 0 then result = result .. valMap[val] .. posMap[pos] else result = result .. valMap[val] end
end
result = result:gsub(valMap[0] .. valMap[0], valMap[0])
return result:gsub(valMap[0] .. valMap[0], valMap[0])
end
-- 把数字串按千分位四位数分割,进行转换为中文
local function formatNum(num, t)
local digitUnit, wordFigure
local result = ""
num = tostring(num)
if tonumber(t) < 1 then digitUnit = { "", "", "", "" } else digitUnit = { "", "", "", "" } end
if tonumber(t) < 1 then
wordFigure = { "", "", "", "", "", "", "", "", "", "" }
else
wordFigure = { "", "", "", "", "", "", "", "", "", "" }
end
if string.len(num) > 4 or tonumber(num) == 0 then return wordFigure[1] end
local lens = string.len(num)
for i = 1, lens do
local n = wordFigure[tonumber(string.sub(num, -i, -i)) + 1]
if n ~= wordFigure[1] then result = n .. digitUnit[i] .. result else result = n .. result end
end
result = result:gsub(wordFigure[1] .. wordFigure[1], wordFigure[1])
result = result:gsub(wordFigure[1] .. "$", "")
result = result:gsub(wordFigure[1] .. "$", "")
return result
end
-- 数值转换为中文
local function number2cnChar(num, flag, digitUnit, wordFigure) --flag=0中文小写反之为大写
local result = ""
if tonumber(flag) < 1 then
digitUnit = digitUnit or { [1] = "", [2] = "亿" }
wordFigure = wordFigure or { [1] = "", [2] = "", [3] = "", [4] = "" }
else
digitUnit = digitUnit or { [1] = "", [2] = "亿" }
wordFigure = wordFigure or { [1] = "", [2] = "", [3] = "", [4] = "" }
end
local lens = string.len(num)
if lens < 5 then
result = formatNum(num, flag)
elseif lens < 9 then
result = formatNum(string.sub(num, 1, -5), flag) .. digitUnit[1] .. formatNum(string.sub(num, -4, -1), flag)
elseif lens < 13 then
result = formatNum(string.sub(num, 1, -9), flag) ..
digitUnit[2] ..
formatNum(string.sub(num, -8, -5), flag) .. digitUnit[1] .. formatNum(string.sub(num, -4, -1), flag)
else
result = ""
end
result = result:gsub("^" .. wordFigure[1], "")
result = result:gsub(wordFigure[1] .. digitUnit[1], "")
result = result:gsub(wordFigure[1] .. digitUnit[2], "")
result = result:gsub(wordFigure[1] .. wordFigure[1], wordFigure[1])
result = result:gsub(wordFigure[1] .. "$", "")
if lens > 4 then result = result:gsub("^" .. wordFigure[2] .. wordFigure[3], wordFigure[3]) end
if result ~= "" then result = result .. wordFigure[4] else result = "数值超限!" end
return result
end
local function number2zh(num, t)
local result, wordFigure
result = ""
if tonumber(t) < 1 then
wordFigure = { "", "", "", "", "", "", "", "", "", "" }
else
wordFigure = { "", "", "", "", "", "", "", "", "", "" }
end
if tostring(num) == nil then return "" end
for pos = 1, string.len(num) do
result = result .. wordFigure[tonumber(string.sub(num, pos, pos) + 1)]
end
result = result:gsub(wordFigure[1] .. wordFigure[1], wordFigure[1])
return result:gsub(wordFigure[1] .. wordFigure[1], wordFigure[1])
end
local function number_translatorFunc(num)
local numberPart = splitNumPart(num)
local result = {}
if numberPart.dot ~= "" then
table.insert(result,
{ number2cnChar(numberPart.int, 0, { "", "亿" }, { "", "", "", "" }) .. number2zh(numberPart.dec, 0),
"" })
-- table.insert(result,
-- { number2cnChar(numberPart.int, 1, { "萬", "億" }, { "", "一", "十", "点" }) .. number2zh(numberPart.dec, 1),
-- "〔数字大写〕" })
local upperRaw = number2cnChar(numberPart.int, 1, { "", "" }, { "", "", "", "" })
local upper = upperRaw:gsub("^拾", "壹拾") .. number2zh(numberPart.dec, 1)
table.insert(result, { upper, "" })
else
table.insert(result, { number2cnChar(numberPart.int, 0, { "", "亿" }, { "", "", "", "" }), "" })
table.insert(result,
{ number2cnChar(numberPart.int, 1, { "", "" }, { "", "", "", "" }):gsub("^拾", "壹拾"), "" })
end
table.insert(result,
{ number2cnChar(numberPart.int, 0) ..
decimal_func(numberPart.dec, { [1] = "", [2] = "", [3] = "", [4] = "" },
{ [0] = "", "", "", "", "", "", "", "", "", "" }), "" })
local number2cnCharInt = number2cnChar(numberPart.int, 1)
local number2cnCharDec = decimal_func(numberPart.dec, { [1] = "", [2] = "", [3] = "", [4] = "" },
{ [0] = "", "", "", "", "", "", "", "", "", "" })
if string.len(numberPart.int) > 4 and number2cnCharInt:find('^拾[壹贰叁肆伍陆柒捌玖]?') and number2cnCharInt:find('[万亿]') then -- 简易地规避 utf8 匹配问题
local number2cnCharInt_var = number2cnCharInt:gsub('^拾', '壹拾')
table.insert(result, { number2cnCharInt_var .. number2cnCharDec, "" })
-- 会计书写要求 https://github.com/iDvel/rime-ice/issues/989
else
table.insert(result, { number2cnCharInt .. number2cnCharDec, "" })
end
local result = { result[1], result[4], result[2], result[3] }
return result
end
local function number_translator(input, seg, env)
-- 获取 recognizer/patterns/number 的第 2 个字符作为触发前缀
env.number_keyword = env.number_keyword or
env.engine.schema.config:get_string('recognizer/patterns/number'):sub(2, 2)
local str, num, numberPart
if env.number_keyword ~= '' and input:sub(1, 1) == env.number_keyword then
local context = env.engine.context
local segment = context.composition:back()
-- 设置手动排序的排序编码以支持 N 指令的手动排序
context:set_property("sequence_adjustment_code", env.number_keyword)
str = string.gsub(input, "^(%a+)", "")
numberPart = number_translatorFunc(str)
if str and #str > 0 and #numberPart > 0 then
-- 设置标签
segment.tags = segment.tags + Set({ "number" })
for i = 1, #numberPart do
yield(Candidate(input, seg.start, seg._end, numberPart[i][1], numberPart[i][2]))
end
end
end
end
-- print(#number_translatorFunc(3355.433))
return number_translator