
このScribuntoモジュールの解説ページを作成することができます。 編集者は、このモジュールをサンドボックス (作成 | 複製)とテストケース (作成)で試すことができます。(解説) このモジュールのサブページ一覧。 |
local errormsg = ('[[Category:不明な通貨を含む記事]]' .. '<span class="exchangeinfo" style="display:none;" ' .. 'title="不明な為替レート">不明な通貨</span>' .. 'レートが見つかりません') local function countSigificantDigits(number) number = string.gsub(number, '%.', '', 1) number = mw.text.trim(number, '0') return #number end local function round(num, numSigificantDigits) local numDecimalPlaces = numSigificantDigits - math.floor(math.log10(num)) - 1 local mult = 10^(numDecimalPlaces or 0) return math.floor(num * mult + 0.5) / mult end local function getTabularDataFieldNames(tabularData) local fields = {} for _,field in pairs(tabularData.schema.fields) do table.insert(fields, field.name) end return fields end local function getColumnIndices(fields) local rowCurrencyIndex, dateIndex local targetCurrencyIndices = {} local sourceCurrencyIndices = {} for i,v in pairs(fields) do if v == 'currency' then rowCurrencyIndex = i elseif v == 'date' then dateIndex = i elseif string.match(v, '^%u%u%u$') then sourceCurrencyIndices[v] = i elseif string.match(v, '^_%u%u%u$') then targetCurrencyIndices[string.sub(v,2)] = i end end return rowCurrencyIndex, dateIndex, sourceCurrencyIndices, targetCurrencyIndices end local function getConversionTable(dataPageName) local tabularData = mw.ext.data.get(dataPageName) if not tabularData then return nil end local fields = getTabularDataFieldNames(tabularData) local rowCurrencyIndex, dateIndex, sourceCurrencyIndices, targetCurrencyIndices = getColumnIndices(fields) local conversionTable = {} if rowCurrencyIndex then for _,row in pairs(tabularData.data) do for sourceCurrency,index in pairs(sourceCurrencyIndices) do if not conversionTable[sourceCurrency] then conversionTable[sourceCurrency] = {} end conversionTable[sourceCurrency][row[rowCurrencyIndex]] = {rate = row[index], revisionTime = row[dateIndex]} end for targetCurrency,index in pairs(targetCurrencyIndices) do if not conversionTable[row[rowCurrencyIndex]] then conversionTable[row[rowCurrencyIndex]] = {} end conversionTable[row[rowCurrencyIndex]][targetCurrency] = {rate = row[index], revisionTime = row[dateIndex]} end end end return conversionTable end local function getDataFromRateDataPage(dataPageName, source, target) local conversionTable = getConversionTable(dataPageName) if not conversionTable then return nil end local rate, revisionTime if conversionTable[source] and conversionTable[source][target] then rate = conversionTable[source][target]['rate'] rateSignificantDigits = countSigificantDigits(rate) revisionTime = conversionTable[source][target]['revisionTime'] elseif conversionTable[target] and conversionTable[target][source] then local targetToSourceRate = conversionTable[target][source]['rate'] rate = targetToSourceRate^-1 rateSignificantDigits = countSigificantDigits(targetToSourceRate) revisionTime = conversionTable[target][source]['revisionTime'] end return rate, rateSignificantDigits, revisionTime end local p = {} function p._rate(source, target, rounded) local dataPageNames = { 'ECB euro foreign exchange reference rates.tab', 'Xe.com exchange rates.tab'} local rate, revisionTime, rateSignificantDigits for _,name in pairs(dataPageNames) do rate, rateSignificantDigits, revisionTime = getDataFromRateDataPage(name, source, target) if not rate or not revisionTime then for _,name in pairs(dataPageNames) do local USDtoTargetRate, UtoTSigDig, UtoTRevTime = getDataFromRateDataPage(name, 'USD', target) local USDtoSourceRate, UtoSSigDig, UtoSRevTime = getDataFromRateDataPage(name, 'USD', source) if USDtoTargetRate and USDtoSourceRate then rate = USDtoTargetRate/USDtoSourceRate revisionTime = UtoTRevTime < UtoSRevTime and UtoTRevTime or UtoSRevTime rateSignificantDigits = UtoTSigDig < UtoSSigDig and UtoTSigDig or UtoSSigDig end end end if rate and revisionTime then break end end if rate and revisionTime then if rounded then rate = round(rate, rateSignificantDigits) end return rate, revisionTime end end function p._convert(source, target, amount) local rate = p._rate(source, target) if rate then local amountSigificantDigitsCount = countSigificantDigits(amount) return round(amount * rate, amountSigificantDigitsCount + 1) end end function p._convertSingelOrRange(source, target, amounts) local amounts = string.gsub(amounts, ',', '') local splitOffset = mw.ustring.find(amounts, '-') local converted if splitOffset then local firstAmount = mw.ustring.sub(amounts, 0, splitOffset -1) local secondAmount = mw.ustring.sub(amounts, splitOffset + 1) local first = p._convert(source, target, firstAmount) local second = p._convert(source, target, secondAmount) converted = first and second and first .. '–' .. second else converted = p._convert(source, target, amounts) end return converted end function p.rate(frame) local args = frame.args local rate = p._rate(args.source, args.target, true) local result = rate or args.verbose and errormsg return result end function p.revisionTime(frame) local args = frame.args local _,revisionTime = p._rate(args.source, args.target) local result = revisionTime or args.verbose and errormsg return result end function p.convert(frame) local args = frame.args local amount = string.gsub(args.amount, ',', '') local convertedAmount = p._convert(args.source, args.target, amount) local result = convertedAmount or args.verbose and errormsg return result end function p.convertSingelOrRange(frame) local args = frame.args local convertedAmounts = p._convertSingelOrRange( args.source, args.target, args.amounts) local result = convertedAmounts or args.verbose and errormsg return result end local function currencyWithSymbol(currency, symbolFormat, amount) local currencyWithSymbol = ( symbolFormat and string.format(symbolFormat, amount) or currency .. amount) return currencyWithSymbol end function p.currencyWithConversions(frame) local args = frame.args local amount = (args.amount and args.amount ~= '') and args.amount or 1 local i18n = mw.loadData('Module:Exchangerate/i18n') local currencySymbols = i18n.symbols[args.currency] local shortSymbol = currencySymbols and currencySymbols.shortSymbol local currencyWithShortSymbol = currencyWithSymbol( args.currency, shortSymbol, amount) local uniqueSymbol = currencySymbols and currencySymbols.uniqueSymbol local currencyWithUniqueSymbol = currencyWithSymbol( args.currency, uniqueSymbol, amount) local conversionCurrencies = i18n.defaultConversions or {'USD', 'EUR'} local convertedStrings = {} for _,convCurrency in ipairs(conversionCurrencies) do if args.currency ~= convCurrency then local convertedAmount = p._convertSingelOrRange( args.currency, convCurrency, amount) local convCurrencyUniqueSymbol = (i18n.symbols[convCurrency] and i18n.symbols[convCurrency].uniqueSymbol) local convCurrencyWithSymbol = convertedAmount and currencyWithSymbol( convCurrency, convCurrencyUniqueSymbol, convertedAmount) table.insert(convertedStrings, convCurrencyWithSymbol) end end local comma = mw.message.new('comma-separator'):plain() local allConvertedStrings = table.concat(convertedStrings, comma) local conversions = (allConvertedStrings ~= '') and ' ≈ ' .. allConvertedStrings or '' local resultFormat = '<abbr title="%s%s">%s</abbr>' local result = string.format(resultFormat, currencyWithUniqueSymbol, conversions, currencyWithShortSymbol) return result end return p