Module:В чи у
From Test Wiki
Documentation for this module may be created at Module:В чи у/doc
local p = {}
-- Таблиця для перетворення чисел на слова (останнє слово числівника)
local numberWords = {
-- Одиниці
["0"] = "нуль",
["1"] = "один",
["2"] = "два",
["3"] = "три",
["4"] = "чотири",
["5"] = "п'ять",
["6"] = "шість",
["7"] = "сім",
["8"] = "вісім",
["9"] = "дев'ять",
["10"] = "десять",
["11"] = "одинадцять",
["12"] = "дванадцять",
["13"] = "тринадцять",
["14"] = "чотирнадцять",
["15"] = "п'ятнадцять",
["16"] = "шістнадцять",
["17"] = "сімнадцять",
["18"] = "вісімнадцять",
["19"] = "дев'ятнадцять",
["20"] = "двадцять",
["30"] = "тридцять",
["40"] = "сорок",
["50"] = "п'ятдесят",
["60"] = "шістдесят",
["70"] = "сімдесят",
["80"] = "вісімдесят",
["90"] = "дев'яносто",
["100"] = "сто",
["200"] = "двісті",
["300"] = "триста",
["400"] = "чотириста",
["500"] = "п'ятсот",
["600"] = "шістсот",
["700"] = "сімсот",
["800"] = "вісімсот",
["900"] = "дев'ятсот",
["1000"] = "тисяча",
["2000"] = "дві тисячі",
["1000000"] = "мільйон",
["1000000000"] = "мільярд",
["1000000000000"] = "трильйон"
}
-- Функція для визначення, чи є символ голосним
local function isVowel(char)
local vowels = "аеєиіїоуюяАЕЄИІЇОУЮЯ"
return vowels:find(char, 1, true) ~= nil
end
-- Функція для визначення, чи є символ приголосним
local function isConsonant(char)
local consonants = "бвгґджзклмнпрстфхцчшщйБВГҐДЖЗКЛМНПРСТФХЦЧШЩЙ"
return consonants:find(char, 1, true) ~= nil
end
-- Функція для визначення останнього слова складеного числівника
local function getLastWordOfNumber(num)
-- Видаляємо пробіли та коми
num = tostring(num):gsub("[%s,]", "")
-- Перевіряємо, чи це число
if not num:match("^%d+$") then
return nil
end
local n = tonumber(num)
if not n then
return nil
end
-- Для великих чисел визначаємо порядок
if n >= 1000000000000 then
local remainder = n % 1000000000000
if remainder == 0 then
return "трильйон"
else
return getLastWordOfNumber(remainder)
end
elseif n >= 1000000000 then
local remainder = n % 1000000000
if remainder == 0 then
return "мільярд"
else
return getLastWordOfNumber(remainder)
end
elseif n >= 1000000 then
local remainder = n % 1000000
if remainder == 0 then
return "мільйон"
else
return getLastWordOfNumber(remainder)
end
elseif n >= 1000 then
local remainder = n % 1000
if remainder == 0 then
local thousands = math.floor(n / 1000)
if thousands == 1 then
return "тисяча"
elseif thousands == 2 then
return "тисячі"
else
return "тисяч"
end
else
return getLastWordOfNumber(remainder)
end
elseif n >= 100 then
local remainder = n % 100
if remainder == 0 then
return numberWords[tostring(n)]
else
return getLastWordOfNumber(remainder)
end
elseif n >= 20 then
local remainder = n % 10
if remainder == 0 then
return numberWords[tostring(n)]
else
return numberWords[tostring(remainder)]
end
else
return numberWords[tostring(n)]
end
end
-- Функція для отримання першого слова числівника
local function getFirstWordOfNumber(num)
num = tostring(num):gsub("[%s,]", "")
if not num:match("^%d+$") then
return nil
end
local n = tonumber(num)
if not n then
return nil
end
-- Визначаємо перше слово
if n >= 1000000000000 then
local trillions = math.floor(n / 1000000000000)
return getLastWordOfNumber(trillions)
elseif n >= 1000000000 then
local billions = math.floor(n / 1000000000)
return getLastWordOfNumber(billions)
elseif n >= 1000000 then
local millions = math.floor(n / 1000000)
return getLastWordOfNumber(millions)
elseif n >= 1000 then
local thousands = math.floor(n / 1000)
return getLastWordOfNumber(thousands)
else
return numberWords[tostring(n)]
end
end
-- Функція для отримання останнього символу слова або числа
local function getLastChar(word)
if not word or word == "" then
return nil
end
word = word:match("^%s*(.-)%s*$")
-- Якщо це число
if word:match("^%d+$") then
local lastWord = getLastWordOfNumber(word)
if lastWord then
return mw.ustring.sub(lastWord, -1)
end
end
return mw.ustring.sub(word, -1)
end
-- Функція для отримання першого символу слова або числа
local function getFirstChar(word)
if not word or word == "" then
return nil
end
word = word:match("^%s*(.-)%s*$")
-- Якщо це число
if word:match("^%d+$") then
local firstWord = getFirstWordOfNumber(word)
if firstWord then
return mw.ustring.sub(firstWord, 1, 1)
end
end
return mw.ustring.sub(word, 1, 1)
end
-- Перевірка на спеціальні буквосполучення (в, ф, льв, зв, св, дв, тв, гв, хв)
local function startsWithSpecialCombination(word)
if not word or word == "" then
return false
end
word = word:match("^%s*(.-)%s*$")
-- Якщо це число, перевіряємо його текстове представлення
if word:match("^%d+$") then
local firstWord = getFirstWordOfNumber(word)
if firstWord then
word = firstWord
end
end
local lower = mw.ustring.lower(word)
-- Перевірка на в або ф
if lower:sub(1, 1) == "в" or lower:sub(1, 1) == "ф" then
return true
end
-- Перевірка на буквосполучення льв, зв, св, дв, тв, гв, хв
local specialCombinations = {"льв", "зв", "св", "дв", "тв", "гв", "хв"}
for _, combo in ipairs(specialCombinations) do
if mw.ustring.sub(lower, 1, mw.ustring.len(combo)) == combo then
return true
end
end
return false
end
-- Перевірка, чи слово починається з кількох приголосних
local function startsWithMultipleConsonants(word)
if not word or word == "" then
return false
end
word = word:match("^%s*(.-)%s*$")
-- Якщо це число, перевіряємо його текстове представлення
if word:match("^%d+$") then
local firstWord = getFirstWordOfNumber(word)
if firstWord then
word = firstWord
end
end
if mw.ustring.len(word) < 2 then
return false
end
local firstChar = mw.ustring.sub(word, 1, 1)
local secondChar = mw.ustring.sub(word, 2, 2)
return isConsonant(firstChar) and isConsonant(secondChar)
end
-- Основна функція для визначення прийменника
function p.determine(frame)
local args = frame.args
if not args[1] or args[1] == "" then
args = frame:getParent().args
end
local previousWord = args[1] or ""
local nextWord = args[2] or ""
-- Видаляємо пробіли
previousWord = previousWord:match("^%s*(.-)%s*$")
nextWord = nextWord:match("^%s*(.-)%s*$")
-- Якщо немає наступного слова, повертаємо порожній рядок
if nextWord == "" then
return ""
end
local lastChar = getLastChar(previousWord)
local firstChar = getFirstChar(nextWord)
-- Правило 1.4: перед в, ф та спеціальними буквосполученнями завжди "у"
if startsWithSpecialCombination(nextWord) then
return "у"
end
-- Правило 1.3: якщо наступне слово починається з кількох приголосних
if startsWithMultipleConsonants(nextWord) then
return "у"
end
-- Якщо попереднє слово порожнє або його немає
if previousWord == "" or not lastChar then
-- На початку речення
if isVowel(firstChar) then
return "в" -- Правило 2.2
else
return "у" -- Правило 1.2
end
end
-- Якщо попереднє слово закінчується на голосний
if isVowel(lastChar) then
if isVowel(firstChar) then
return "в" -- Правило 2.1
elseif startsWithSpecialCombination(nextWord) then
return "у" -- Правило 1.4
else
return "в" -- Правило 2.6 (за замовчуванням після голосного перед більшістю приголосних)
end
end
-- Якщо попереднє слово закінчується на приголосний
if isConsonant(lastChar) then
if isVowel(firstChar) then
return "в" -- Правило 2.3
else
return "у" -- Правило 1.1
end
end
-- За замовчуванням
return "у"
end
-- Функція для використання в шаблоні з автоматичним додаванням слів
function p.full(frame)
local args = frame.args
if not args[1] or args[1] == "" then
args = frame:getParent().args
end
local previousWord = args[1] or ""
local nextWord = args[2] or ""
-- Видаляємо пробіли
previousWord = previousWord:match("^%s*(.-)%s*$")
nextWord = nextWord:match("^%s*(.-)%s*$")
local preposition = p.determine(frame)
-- Формуємо результат: перше слово + прийменник + друге слово
local result = ""
if previousWord ~= "" then
result = previousWord .. " " .. preposition .. " " .. nextWord
else
-- Якщо немає першого слова (початок речення)
result = preposition .. " " .. nextWord
end
return result
end
return p