Module:Unité : Différence entre versions
(bug si trop de chiffre après la virgule) |
(retouche de la modification précédente) |
||
(33 révisions intermédiaires par le même utilisateur non affichées) | |||
Ligne 1 : | Ligne 1 : | ||
− | local p = { } | + | local p = {} |
+ | -- local Delink = require( 'Module:Delink' ) -- chargé uniquement si nécessaire | ||
+ | |||
+ | -- Chargement de la base de données des nom d'unités avec gestion d'erreur. | ||
+ | local moduleData = 'Module:Unité/Data' | ||
+ | local dataSuccess, Data = pcall ( mw.loadData, moduleData ) | ||
+ | if dataSuccess and type( Data ) == 'table' then | ||
+ | dataSuccess = type( Data.unit ) == 'table' | ||
+ | and type( Data.prefix ) == 'table' | ||
+ | and type( Data.exposant ) == 'table' | ||
+ | end | ||
+ | |||
+ | local errorCat = '[[Catégorie:Page incorrectement traitée par le Module:Unité]]' | ||
+ | local addErrorCat = false | ||
+ | |||
+ | local supUnicode = { ['0'] = '⁰', ['1'] = '¹', ['2'] = '²', ['3'] = '³', ['4'] = '⁴', ['5'] = '⁵', ['6'] = '⁶', ['7'] = '⁷', ['8'] = '⁸', ['9'] = '⁹', | ||
+ | ['+'] = '⁺', ['-'] = '⁻', ['='] = '⁼', ['('] = '⁽', [')'] = '⁾', ['n'] = 'ⁿ' } | ||
+ | local subUnicode = { ['0'] = '₀', ['1'] = '₁', ['2'] = '₂', ['3'] = '₃', ['4'] = '₄', ['5'] = '₅', ['6'] = '₆', ['7'] = '₇', ['8'] = '₈', ['9'] = '₉', | ||
+ | ['+'] = '₊', ['-'] = '₋', ['='] = '₌', ['('] = '₍', [')'] = '₎', | ||
+ | ['a'] = 'ₐ', ['e'] = 'ₑ', ['o'] = 'ₒ', ['x'] = 'ₓ', ['h'] = 'ₕ', ['k'] = 'ₖ', ['l'] = 'ₗ', | ||
+ | ['m'] = 'ₘ', ['n'] = 'ₙ', ['p'] = 'ₚ', ['s'] = 'ₛ', ['t'] = 'ₜ', | ||
+ | } | ||
--- Copie de Outils.trim acceptant les nombres. | --- Copie de Outils.trim acceptant les nombres. | ||
local function trim( texte ) | local function trim( texte ) | ||
if type( texte ) == 'string' then | if type( texte ) == 'string' then | ||
− | texte = texte:gsub( '^%s*(. | + | texte = texte:gsub( '^%s*(%S?.-)%s*$', '%1' ) |
if texte ~= '' then | if texte ~= '' then | ||
return texte | return texte | ||
Ligne 10 : | Ligne 31 : | ||
elseif type( texte ) == 'number' then | elseif type( texte ) == 'number' then | ||
return tostring( texte ) | return tostring( texte ) | ||
+ | end | ||
+ | end | ||
+ | |||
+ | function p.sanitizeNum( nombre ) | ||
+ | if type( nombre ) == 'number' then | ||
+ | return tostring( nombre ) | ||
+ | elseif trim( nombre ) then | ||
+ | local result = nombre | ||
+ | -- trim | ||
+ | :gsub( '^%s*(.*)%f[%s]%s*$', '%1' ) | ||
+ | -- remplacement des signes moins ou demi-cadratin par un tiret | ||
+ | :gsub( '%−%f[%d]', '-') -- U+2212 | ||
+ | :gsub( '−%f[%d]', '-') -- html − | ||
+ | :gsub( '\226\128[\146\147]%f[%d]', '-') -- U+2212, U+2213 (tiret numérique et demi-cadratin) | ||
+ | -- remplacement des espaces insécable par des espace simple | ||
+ | :gsub( '\194\160', ' ' ) | ||
+ | result = mw.ustring.gsub( result, '[ - ]', ' ' ) -- U+2002 à U+220A et U+202F | ||
+ | return result | ||
+ | else | ||
+ | return '' | ||
end | end | ||
end | end | ||
--- | --- | ||
− | -- parseNum transforme si possible une chaine | + | -- parseNum transforme si possible une chaine formatée en un chaine interprétable par tonumber() |
-- retourne une chaine pour éviter les arrondi éventuels de lua. | -- retourne une chaine pour éviter les arrondi éventuels de lua. | ||
− | -- si nombre n'est pas un | + | -- si "nombre" est une chaine non reconnue comme un nombre par la fonction, retourne "nombre". |
− | + | -- si "nombre" n'est pas un number ou une chaine retourne une chaine vide. | |
function p.parseNombre( nombre ) | function p.parseNombre( nombre ) | ||
+ | local result | ||
if type( nombre ) == 'number' then | if type( nombre ) == 'number' then | ||
− | + | return tostring( nombre ) | |
− | + | else | |
− | + | -- remplacement des signes moins ou demi-cadratin par un tiret | |
+ | result = p.sanitizeNum( nombre ) | ||
+ | if result == '' then | ||
+ | return '' | ||
+ | elseif not result:match( '^%-?[%d., ]*%d$' ) then | ||
+ | return nombre | ||
+ | end | ||
end | end | ||
− | -- | + | -- suppression espaces |
− | + | result = result:gsub( ' ', '' ) | |
− | |||
− | |||
− | if | + | -- gestion des points et des virgules |
− | + | if result:match( '[.,]' ) then | |
− | + | if result:match( '%d%.%d%d%d%.%d' ) then | |
− | + | -- type 12.345.678 | |
− | + | result = result:gsub( '%.', '' ):gsub( ',', '.' ) | |
− | + | elseif result:match( '%d,%d%d%d,%d' ) -- type 1,234,567 ou 1.234,567,8 | |
− | + | or result:match( '%d,%d%d%d%.%d' ) -- format anglo-saxon type 1,234.5 | |
− | + | or result:match( '%d%.%d%d%d,%d' ) -- type 1.123,56 (utilisé en exemple pour sépararer les décimales avec l'ancien modèle unité ou formatnum) | |
− | + | then | |
− | + | result = result:gsub( ',', '' ) | |
− | + | else | |
− | + | result = result:gsub( ',', '.' ) | |
− | |||
− | |||
− | |||
− | |||
− | |||
end | end | ||
end | end | ||
− | return | + | return result |
end | end | ||
Ligne 56 : | Ligne 97 : | ||
-- _formantNum transforme un nombre ou une chaine représentant un nombre en chaine formatée suivant les conventions du français | -- _formantNum transforme un nombre ou une chaine représentant un nombre en chaine formatée suivant les conventions du français | ||
-- si le paramètre ne représente pas un nombre lua il est retourné sans modification | -- si le paramètre ne représente pas un nombre lua il est retourné sans modification | ||
− | function p. | + | function p.formatNum( num ) |
+ | local params = {} | ||
+ | if type( num ) == 'table' then | ||
+ | params = num | ||
+ | num = params[1] | ||
+ | end | ||
if type( num ) == 'number' then | if type( num ) == 'number' then | ||
num = tostring( num ) | num = tostring( num ) | ||
− | elseif type( num ) ~= 'string' then | + | elseif type( num ) ~= 'string' or num == '' then |
return num | return num | ||
end | end | ||
− | local moins, entier, fraction = num:match( '^(%-?)(%d | + | -- séparation exposant |
+ | local n, exponent = num:match( '^([-%d.]+)e([+-]?%d+)$' ) | ||
+ | if exponent then | ||
+ | num = n | ||
+ | if params.noHtml then | ||
+ | exponent = exponent:gsub('+?%f[%d]0', '' ) | ||
+ | :gsub( '[%d-]', supUnicode ) | ||
+ | else | ||
+ | exponent = '<sup>' .. exponent:gsub('^%+?(%-?)0?', { ['-'] = '−' } ) .. '</sup>' | ||
+ | end | ||
+ | exponent = ' ×10' .. exponent | ||
+ | else | ||
+ | exponent = '' | ||
+ | end | ||
+ | |||
+ | -- arrondi | ||
+ | decimals = tonumber( params.decimals ) | ||
+ | round = tonumber( params.round ) or decimals | ||
+ | if round then | ||
+ | local mult = 10 ^ round | ||
+ | num = tostring( math.floor( num * mult + 0.5 ) / mult ) | ||
+ | end | ||
+ | |||
+ | local moins, entier, fraction = num:match( '^(%-?)(%d*)%.?(%d*)$' ) | ||
if not entier then | if not entier then | ||
return num | return num | ||
Ligne 72 : | Ligne 141 : | ||
end | end | ||
− | if entier:len() > 3 then | + | if entier == '' then |
− | local ini = math.fmod( entier:len(), 3 ) | + | entier = '0' |
+ | elseif entier:len() > 3 then | ||
+ | local ini = math.fmod( entier:len() - 1, 3 ) + 1 | ||
entier = ( entier:sub( 1, ini ) or '') .. entier:sub( ini + 1 ):gsub( '(%d%d%d)', '\194\160%1' ) | entier = ( entier:sub( 1, ini ) or '') .. entier:sub( ini + 1 ):gsub( '(%d%d%d)', '\194\160%1' ) | ||
end | end | ||
− | if fraction ~= '' then | + | if fraction ~= '' or ( decimals and decimals > 0 ) then |
− | fraction = ',' .. fraction:gsub( '(%d%d%d)', '%1\194\160' ):gsub( '\194\160$', '' ) | + | if decimals and decimals > #fraction then |
+ | fraction = fraction .. string.rep( '0', decimals - #fraction ) | ||
+ | end | ||
+ | if #fraction > 4 then | ||
+ | fraction = ',' .. fraction:gsub( '(%d%d%d)', '%1\194\160' ):gsub( '\194\160$', '' ) | ||
+ | else | ||
+ | fraction = ',' .. fraction | ||
+ | end | ||
end | end | ||
− | + | ||
− | return moins .. entier .. fraction | + | return moins .. entier .. fraction .. exponent |
end | end | ||
--- | --- | ||
− | -- | + | -- formatNombre transforme un nombre formaté ou non en chaine formatée suivant les convention du français. |
− | + | -- si la chaine n'est pas reconnu comme un nombre, elle n'est pas modifiée. | |
− | + | function p.formatNombre( num, round, decimals ) | |
− | + | return p.formatNum{ p.parseNombre( num ), round, decimals } | |
− | |||
− | |||
− | |||
end | end | ||
− | function p. | + | --- formatNombres transforme tous les nombres d'une chaine en nombre formaté suivant les conventions du français. |
− | return p. | + | function p.formatNombres( nombres, round, decimals ) |
+ | if type( nombres ) == 'number' then | ||
+ | return p.formatNum( nombres, round, decimals ) | ||
+ | elseif type( nombres ) == 'string' then | ||
+ | -- retire les chiffres des strip marker | ||
+ | local strip, i = {}, 0 | ||
+ | nombres = nombres:gsub( | ||
+ | 'UNIQ%-%-%a+%-%x%x%x%x%x%x%x%x%-QINU', | ||
+ | function ( marker ) | ||
+ | i = i + 1 | ||
+ | strip[ tostring( i ) ] = marker | ||
+ | return 'UNIQ^' .. i .. '¤QINU' | ||
+ | end | ||
+ | ) | ||
+ | -- formatage proprement dit | ||
+ | nombres = p.sanitizeNum( nombres ) | ||
+ | nombres = nombres:gsub( | ||
+ | '%-?%f[%d.,^][%d., ]+%f[%D]', | ||
+ | function ( n ) | ||
+ | return p.formatNombre( n, round, decimals ) | ||
+ | end | ||
+ | ) | ||
+ | -- réintroduction des strip marker | ||
+ | nombres = nombres:gsub( 'UNIQ^(%d+)¤QINU', strip ) | ||
+ | return nombres | ||
+ | else | ||
+ | return '' | ||
+ | end | ||
end | end | ||
function p.parseUnit( texte ) | function p.parseUnit( texte ) | ||
− | + | local toParse = p.sanitizeNum( texte ) | |
− | + | if toParse ~= '' then | |
local result | local result | ||
+ | local specificArgs = { | ||
+ | ['à'] = 'à', | ||
+ | et = 'et', | ||
+ | ou = 'ou', | ||
+ | ['–'] = '–', -- demi cadratin | ||
+ | ['±'] = '±', ['+-'] = '±', ['+/-'] = '±', | ||
+ | ['+'] = '+', | ||
+ | ['−'] = '−', ['-'] = '−', -- signe moins et tiret | ||
+ | ['×'] = '×', x = '×', ['*'] = '×', | ||
+ | ['××'] = '××', xx = '××', ['**'] = '××', | ||
+ | } | ||
+ | |||
-- valeur numérique | -- valeur numérique | ||
− | local | + | local match, capture = toParse:match( '^((%-?%f[%d.,][%d., ]*%d%f[%D])%s*)' ) |
− | if nombre then | + | result = { capture or false } |
− | toParse = toParse:sub( | + | if match then |
+ | toParse = toParse:sub( match:len() + 1 ) | ||
+ | |||
+ | -- fraction | ||
+ | match, capture = toParse:match( '^(([+-]?%d* ?/ ?%d+)%s*)' ) | ||
+ | if not match then | ||
+ | match, capture = mw.ustring.match( toParse, '^(([¼-¾⅐-⅞])%s*)' ) | ||
+ | end | ||
+ | if match then | ||
+ | if capture:match( '^/' ) then | ||
+ | local n = result[1]:match( ' (%d+)$' ) or '' | ||
+ | result[1] = result[1]:sub( 1, -1 - #n ) | ||
+ | result.fraction = n .. capture | ||
+ | else | ||
+ | result.fraction = capture | ||
+ | end | ||
+ | toParse = toParse:sub( match:len() + 1 ) | ||
+ | end | ||
+ | |||
+ | -- lien avec un deuxième nombre | ||
+ | local match2, conj, num = mw.ustring.match( toParse, '^(([àetouM+/−x*×±–-]+) ?(%-?%f[%d.,][%d., ]*%d%f[%D])%s*)' ) | ||
+ | if match2 and specificArgs[ conj ] | ||
+ | and not ( specificArgs[ conj ] == '×' and mw.ustring.match( toParse, '^[×x] ?10 ?e') ) then | ||
+ | result[ specificArgs[ conj ] ] = num | ||
+ | toParse = toParse:sub( match2:len() + 1 ) | ||
+ | end | ||
+ | if result['+'] or result['×'] then | ||
+ | match2, conj, num = mw.ustring.match( toParse, '^(([x*×−-]) ?(%-?%f[%d.,][%d., ]*%d%f[%D])%s*)' ) | ||
+ | if match2 then | ||
+ | if specificArgs[ conj ] == '×' then | ||
+ | result['××'] = num | ||
+ | else | ||
+ | result['−'] = num | ||
+ | end | ||
+ | toParse = toParse:sub( match2:len() + 1 ) | ||
+ | end | ||
+ | end | ||
end | end | ||
− | |||
-- 10 exposant ( \195\151 = ×, signe multiplié) | -- 10 exposant ( \195\151 = ×, signe multiplié) | ||
− | + | match, capture = toParse:match( '^(%s*e(%-?%d+)%s*)' ) | |
+ | if not match then | ||
+ | match, capture = toParse:match( '^(%s*[x\195]\151?10e(%-?%d+)%s*)' ) | ||
+ | end | ||
if match then | if match then | ||
− | + | result.e = capture | |
− | |||
toParse = toParse:sub( match:len() + 1 ) | toParse = toParse:sub( match:len() + 1 ) | ||
end | end | ||
-- unités | -- unités | ||
− | toParse = toParse:gsub( ' | + | if Data.unit[ toParse ] or mw.ustring.match( toParse, '^%a+$' ) or toParse:match( '%b<>' ) then |
− | + | table.insert( result, toParse ) | |
− | + | toParse = '' | |
− | + | elseif toParse ~= '' then | |
− | + | local unit, exp | |
− | + | toParse = toParse:gsub( '²', '2' ):gsub( '³', '3' ) | |
− | + | repeat | |
+ | -- unité contenant un lien | ||
+ | match, unit, exp = mw.ustring.match( toParse, '^((/?[^%s%d/%[%]]*%b[][^%s%d/]*) ?(%-?%d*)%s*)' ) | ||
+ | if not match then | ||
+ | -- unité ne contenant pas de lien | ||
+ | match, unit, exp = mw.ustring.match( toParse, '^((/?[^%s%d/]+) ?(%-?%d*)%s*)' ) | ||
+ | end | ||
+ | if match then | ||
+ | if unit:match( '%-$' ) and exp ~= '' then | ||
+ | unit = unit:gsub( '%-$', '' ) | ||
+ | exp = '-' .. exp | ||
+ | elseif exp == '-' then | ||
+ | unit = match | ||
+ | exp = '' | ||
+ | end | ||
+ | table.insert( result, unit ) | ||
+ | table.insert( result, exp ) | ||
+ | toParse = toParse:sub( match:len() + 1 ) | ||
+ | end | ||
+ | until toParse == '' or not match | ||
end | end | ||
− | if | + | |
+ | if toParse == '' then | ||
+ | return result | ||
+ | else | ||
-- une partie de la chaine n'a pas pu être décodée, on retourne la chaine originale | -- une partie de la chaine n'a pas pu être décodée, on retourne la chaine originale | ||
+ | addErrorCat = true | ||
return { texte } | return { texte } | ||
− | + | end | |
− | |||
− | end | ||
else | else | ||
return { } | return { } | ||
Ligne 136 : | Ligne 308 : | ||
end | end | ||
− | function p. | + | --- |
− | + | -- nomUtnit retourne le nom français du code d'une unité et de son exposant. | |
− | + | -- si le code de l'unité n'est pas reconnu retourne 1 et false, de façon à ajouter false en première position d'une table. | |
− | + | function p.nomUnit( unit, exposant ) | |
− | + | if not dataSuccess or type( unit ) ~= 'string' then | |
− | + | return 1, false | |
+ | end | ||
− | + | -- nettoyage des liens et balise HTML | |
− | + | unit = unit:gsub( '^/' , '' ) | |
− | + | if unit:match( '%[' ) then | |
− | + | local Delink = require( 'Module:Delink' ) | |
− | + | unit = Delink._delink{ unit } | |
− | + | end | |
− | + | if unit:match( '<' ) then | |
− | + | unit = unit:gsub( '%b<>', '' ) | |
end | end | ||
− | if | + | -- récupère le nom de l'unité |
− | + | local unitTab = Data.unit[ unit ] | |
− | + | local unitPrefix = { nom = '' } | |
− | + | if not unitTab then | |
+ | unitTab = Data.unit[ unit:sub( 2 ) ] | ||
+ | unitPrefix = Data.prefix[ unit:sub( 1, 1 ) ] | ||
+ | if not ( unitTab and unitPrefix ) then | ||
+ | -- pour µ, Ki, Mi, Gi... qui sont codé sur deux octets | ||
+ | unitTab = Data.unit[ unit:sub( 3 ) ] | ||
+ | unitPrefix = Data.prefix[ unit:sub( 1, 2 ) ] | ||
+ | if not ( unitTab and unitPrefix ) then | ||
+ | unitTab = false | ||
+ | end | ||
+ | end | ||
+ | end | ||
+ | |||
+ | -- récupère le nom de l'exposant | ||
+ | if trim( exposant ) then | ||
+ | local exp = tonumber( exposant ) | ||
+ | exp = exp and Data.exposant[ math.abs( exp ) ] | ||
+ | exposant = exp or ' puissance ' .. exposant | ||
+ | else | ||
+ | exposant = '' | ||
end | end | ||
− | -- | + | -- assemble les deux partie |
− | if | + | if type( unitTab ) == 'table' and type( unitTab.nom ) == 'string' then |
− | + | return unitPrefix.nom .. unitTab.nom .. exposant | |
− | + | elseif unit:match( '[/%d]' ) then | |
− | + | -- ce n'est pas du texte simple, on anule l'infobule | |
+ | return 1, false | ||
+ | else | ||
+ | return unit .. exposant | ||
+ | end | ||
+ | end | ||
+ | |||
+ | function p._unite( args ) | ||
+ | -- remplacement de certains caractères, pour simplifier les pattern | ||
+ | local nombre = p.sanitizeNum( args[1] ) | ||
+ | if nombre == '' then | ||
+ | nombre = nil | ||
+ | else | ||
+ | -- formatage du nombre | ||
+ | nombre = p.formatNombres( nombre, args.arrondi, args['décimales'] ) | ||
end | end | ||
− | -- | + | local wiki = { nombre } |
− | local | + | |
− | + | -- fraction | |
− | + | if args.fraction then | |
− | + | local nom, den = args.fraction:match( '^(.-)/(.+)$' ) | |
− | + | if nom then | |
+ | if nom:match( '^[ %dn()=+-]+$' ) and den:match( '^[ %daeoxhklmnpst()=+-]$' ) then | ||
+ | nom = nom:gsub( '[%dn()=+-]', supUnicode ) | ||
+ | den = den:gsub( '[%daeoxhklmnpst()=+-]', subUnicode ) | ||
+ | else | ||
+ | nom = '<sup style="font-size: 70%; vertical-align: 0.4em;">' .. nom .. '</sup>' | ||
+ | den = '<sub style="font-size: 70%; vertical-align: 0em;">' .. den .. '</sub>' | ||
+ | end | ||
+ | args.fraction = nom .. '⁄' .. den | ||
+ | end | ||
+ | table.insert( wiki, ' ' .. args.fraction ) | ||
end | end | ||
− | if | + | |
− | + | -- à, et, ou, ×, – (tiret cadratin) | |
− | + | local specificArgs = { '–', 'à', 'et', 'ou', '×', '××', '±' } | |
− | + | for _, name in ipairs( specificArgs ) do | |
− | + | local v = trim( args[ name ] ) | |
+ | if v then | ||
+ | v = p.formatNombres( v ) | ||
+ | if name == '–' and nombre and nombre:match( '^[^−]' ) and v:match( '^[^−]' ) then | ||
+ | -- pas d'espace pour le tiret cadratin entre deux nombres positifs | ||
+ | table.insert( wiki, '–' ) | ||
+ | elseif name == '××' then | ||
+ | table.insert( wiki, ' × ' ) | ||
+ | else | ||
+ | table.insert( wiki, ' ' .. name .. ' ' ) | ||
+ | end | ||
+ | table.insert( wiki, v ) | ||
end | end | ||
− | |||
end | end | ||
-- unités | -- unités | ||
+ | local i = 1 | ||
+ | local unit = trim( args[ 2 * i ] ) | ||
+ | local units = '' | ||
+ | local nomUnits, par = {}, false | ||
while unit do | while unit do | ||
− | if | + | local exp = p.parseNombre( args[ 2 * i + 1 ] ) |
− | + | local sep = '' | |
− | + | -- gestion des exposants | |
− | + | local expUnit = '' | |
− | + | if exp == '' then | |
− | + | if unit:sub( -2 ) == '²' then | |
− | if exp then | + | exp = '2' |
− | + | unit = unit:sub( 1, -3 ) | |
+ | elseif unit:sub( -2 ) == '³' then | ||
+ | exp = '3' | ||
+ | unit = unit:sub( 1, -3 ) | ||
+ | end | ||
+ | end | ||
+ | if #exp > 0 then | ||
+ | expUnit = '<sup>' .. exp:gsub( '^-', '−') .. '</sup>' -- remplace le tiret par un vrai signe moins | ||
end | end | ||
+ | -- gestion de la séparation des unités et des unités en dénominateur | ||
+ | if units ~= '' then | ||
+ | if unit:sub( 1, 1 ) == '/' then | ||
+ | sep = '/' | ||
+ | unit = unit:sub( 2 ) | ||
+ | if not par then | ||
+ | par = true | ||
+ | table.insert( nomUnits, 'par' ) | ||
+ | end | ||
+ | else | ||
+ | sep = '\194\160' -- point médian désactivé : '⋅\194\160' | ||
+ | if exp:match( '^-' ) and not par then | ||
+ | par = true | ||
+ | table.insert( nomUnits, 'par' ) | ||
+ | end | ||
+ | end | ||
+ | end | ||
+ | -- remplacement de l'unité par son symbole | ||
+ | if Data.unit[ unit ] then | ||
+ | -- unit = Data.unit[ unit ].symbole | ||
+ | -- désactivé car ne gère pas les multiple tel mL | ||
+ | end | ||
+ | units = units .. sep .. unit .. expUnit | ||
+ | table.insert( nomUnits, p.nomUnit( unit, exp ) ) | ||
i = i + 1 | i = i + 1 | ||
unit = trim( args[ 2 * i ] ) | unit = trim( args[ 2 * i ] ) | ||
− | |||
end | end | ||
+ | |||
+ | -- conversion | ||
+ | local unitNameString = nomUnits[1] and table.concat( nomUnits, ' ' ) or '' | ||
+ | unitNameString = mw.ustring.gsub( unitNameString, '(%a)s%f[%A]', '%1' ) | ||
+ | local multiple = 1 | ||
+ | local convertTable = Data.convert[ unitNameString ] | ||
+ | if not convertTable and #unitNameString > 5 then | ||
+ | -- gesion des multiples (Kilo, méga, mili...) | ||
+ | local prefix = Data.prefix[ unitNameString:sub( 1, 4 ) ] or Data.prefix[ unitNameString:sub( 1, 5 ) ] | ||
+ | local _, par = unitNameString:find( ' par ' ) | ||
+ | local prefix2 | ||
+ | if par then | ||
+ | prefix2 = Data.prefix[ unitNameString:sub( par + 1, 4 ) ] or Data.prefix[ unitNameString:sub( par + 1, 5 ) ] | ||
+ | end | ||
+ | if prefix and Data.convert[ unitNameString:gsub( '^' .. prefix.nom, '' ) ] then | ||
+ | convertTable = Data.convert[ unitNameString:gsub( '^' .. prefix.nom, '' ) ] | ||
+ | multiple = 10 ^ prefix.puissance | ||
+ | elseif prefix2 and Data.convert[ unitNameString:gsub( ' par ' .. prefix2.nom, '' ) ] then | ||
+ | convertTable = Data.convert[ unitNameString:gsub( ' par ' .. prefix2.nom, '' ) ] | ||
+ | multiple = 1 / 10 ^ prefix2.puissance | ||
+ | elseif prefix and prefix2 and Data.convert[ unitNameString:gsub( '^' .. prefix.nom, '' ):gsub( ' par ' .. prefix2.nom, '' ) ] then | ||
+ | convertTable = Data.convert[ unitNameString:gsub( '^' .. prefix.nom, '' ):gsub( ' par ' .. prefix2.nom, '' ) ] | ||
+ | multiple = 10 ^ prefix.puissance / 10 ^ prefix2.puissance | ||
+ | end | ||
+ | end | ||
+ | if convertTable then | ||
+ | if type( convertTable[1] ) ~= 'table' then | ||
+ | convertTable = { convertTable } | ||
+ | end | ||
+ | for i, v in ipairs( wiki ) do | ||
+ | local n = tonumber( p.parseNombre( v ) ) | ||
+ | if n then | ||
+ | n = n * 10 ^ ( tonumber( p.parseNombre( args.e ) ) or 0 ) | ||
+ | local converted = {} | ||
+ | for _, c in ipairs( convertTable ) do | ||
+ | local nConverted = n | ||
+ | if c.inverse then | ||
+ | nConverted = 1 / n | ||
+ | end | ||
+ | if c.M then | ||
+ | -- M = masse molaire | ||
+ | local M = tonumber( args.M ) | ||
+ | if not M then | ||
+ | break | ||
+ | end | ||
+ | if c.M == '*' then | ||
+ | nConverted = nConverted * M | ||
+ | elseif c.M == '/' then | ||
+ | nConverted = nConverted / M | ||
+ | end | ||
+ | end | ||
+ | nConverted = nConverted * multiple * c[2] + ( c[3] or 0 ) | ||
+ | -- format | ||
+ | nConverted = p.formatNum{ nConverted, round = c.round or 6, noHtml = true } | ||
+ | table.insert( converted, nConverted .. ' '.. c[1] ) | ||
+ | end | ||
+ | wiki[ i ] = '<span title="' .. table.concat( converted, ' ou ' ) ..'">' .. v ..'</span>' | ||
+ | end | ||
+ | end | ||
+ | end | ||
+ | |||
+ | -- incertitude avec + et − séparés | ||
+ | if trim( args['+'] ) then | ||
+ | local approximation = '+' .. p.formatNombre( args['+'] ) .. '' | ||
+ | if trim( args['−'] ) then | ||
+ | approximation = approximation .. '<br> −' .. p.formatNombre( args['−'] ) | ||
+ | end | ||
+ | table.insert( wiki, '<span style="display:inline-block; vertical-align:top; line-height:1em; font-size:80%; text-align:left;">' ) | ||
+ | table.insert( wiki, approximation .. '</span>' ) | ||
+ | end | ||
+ | |||
+ | -- puissance de 10 | ||
+ | local exposant = trim( args.e ) | ||
+ | if exposant then | ||
+ | exposant = p.formatNombre( exposant ) | ||
+ | if nombre then | ||
+ | if trim( args['±'] ) and not nombre:match( '^%(' ) then | ||
+ | table.insert( wiki, 1, '(' ) | ||
+ | table.insert( wiki, ')' ) | ||
+ | end | ||
+ | table.insert( wiki, ' × 10<sup>' .. exposant .. '</sup>' ) | ||
+ | else | ||
+ | table.insert( wiki, '10<sup>' .. exposant .. '</sup>' ) | ||
+ | end | ||
+ | end | ||
+ | |||
+ | -- ajoute une abbréviation si le nom de l'unité est différent de l'unité (en retirant les espace qui peuvent être devenus insécables) | ||
+ | if units and nomUnits[1] and mw.ustring.gsub( table.concat( nomUnits ), '[ \194\160]', '' ) ~= mw.ustring.gsub( units, '[ \194\160]', '' ) then | ||
+ | units = string.format( ' <abbr class=abbr title="%s">%s</abbr>', table.concat( nomUnits, ' ' ), units ) | ||
+ | elseif units ~= '' and units ~= '°' then | ||
+ | units = ' ' .. units | ||
+ | end | ||
+ | table.insert( wiki, units ) | ||
if #wiki > 0 then | if #wiki > 0 then | ||
− | local result = table.concat( wiki ): | + | local result = table.concat( wiki ) |
− | + | if result:match( ' ' ) then | |
+ | return '<span class="nowrap">' .. result .. '</span>' | ||
+ | else | ||
+ | return result | ||
+ | end | ||
end | end | ||
end | end | ||
Ligne 206 : | Ligne 563 : | ||
function p.unite( frame ) | function p.unite( frame ) | ||
local args | local args | ||
− | if type( frame ) == 'table' | + | if type( frame ) == 'table' then |
+ | if type( frame.getParent ) == 'function' then | ||
args = frame:getParent().args; | args = frame:getParent().args; | ||
+ | else | ||
+ | args = frame | ||
+ | end | ||
end | end | ||
if args then | if args then | ||
− | return p._unite( args ) | + | if trim( args[1] ) then |
+ | if args[1]:match('[^%d,. -]') then | ||
+ | local tempArgs = p.parseUnit( trim( args[1] ) ) | ||
+ | if not ( args[2] and tempArgs[2] ) then | ||
+ | for k, v in pairs( tempArgs ) do | ||
+ | args[k] = v | ||
+ | end | ||
+ | end | ||
+ | end | ||
+ | if args[2] and not Data.unit[ args[2] ] and not args[3] and mw.text.trim( args[2] ):match('[%d/ -]') then | ||
+ | local tempArgs = p.parseUnit( trim( args[2] ) ) | ||
+ | args[2] = false | ||
+ | if tempArgs[1] ~= false then | ||
+ | table.insert( tempArgs, 1, false ) | ||
+ | end | ||
+ | for k, v in pairs( tempArgs ) do | ||
+ | if args[k] and v then | ||
+ | addErrorCat = true | ||
+ | end | ||
+ | args[k] = args[k] or v | ||
+ | end | ||
+ | end | ||
+ | end | ||
+ | -- args alias | ||
+ | args['x'] = args['×'] -- lettre x → signe multiplié | ||
+ | if args['+'] then | ||
+ | args['−'] = args['−'] or args['-'] -- tiret → signe moins | ||
+ | else | ||
+ | args['–'] = args['–'] or args['-'] -- tiret → demi-cadratin | ||
+ | end | ||
+ | local cat = '' | ||
+ | if addErrorCat then | ||
+ | cat = errorCat | ||
+ | end | ||
+ | return p._unite( args ) .. cat | ||
end | end | ||
end | end | ||
return p | return p |
Version actuelle datée du 29 mai 2017 à 22:44
La documentation pour ce module peut être créée à Module:Unité/doc
local p = {} -- local Delink = require( 'Module:Delink' ) -- chargé uniquement si nécessaire -- Chargement de la base de données des nom d'unités avec gestion d'erreur. local moduleData = 'Module:Unité/Data' local dataSuccess, Data = pcall ( mw.loadData, moduleData ) if dataSuccess and type( Data ) == 'table' then dataSuccess = type( Data.unit ) == 'table' and type( Data.prefix ) == 'table' and type( Data.exposant ) == 'table' end local errorCat = '[[Catégorie:Page incorrectement traitée par le Module:Unité]]' local addErrorCat = false local supUnicode = { ['0'] = '⁰', ['1'] = '¹', ['2'] = '²', ['3'] = '³', ['4'] = '⁴', ['5'] = '⁵', ['6'] = '⁶', ['7'] = '⁷', ['8'] = '⁸', ['9'] = '⁹', ['+'] = '⁺', ['-'] = '⁻', ['='] = '⁼', ['('] = '⁽', [')'] = '⁾', ['n'] = 'ⁿ' } local subUnicode = { ['0'] = '₀', ['1'] = '₁', ['2'] = '₂', ['3'] = '₃', ['4'] = '₄', ['5'] = '₅', ['6'] = '₆', ['7'] = '₇', ['8'] = '₈', ['9'] = '₉', ['+'] = '₊', ['-'] = '₋', ['='] = '₌', ['('] = '₍', [')'] = '₎', ['a'] = 'ₐ', ['e'] = 'ₑ', ['o'] = 'ₒ', ['x'] = 'ₓ', ['h'] = 'ₕ', ['k'] = 'ₖ', ['l'] = 'ₗ', ['m'] = 'ₘ', ['n'] = 'ₙ', ['p'] = 'ₚ', ['s'] = 'ₛ', ['t'] = 'ₜ', } --- Copie de Outils.trim acceptant les nombres. local function trim( texte ) if type( texte ) == 'string' then texte = texte:gsub( '^%s*(%S?.-)%s*$', '%1' ) if texte ~= '' then return texte end elseif type( texte ) == 'number' then return tostring( texte ) end end function p.sanitizeNum( nombre ) if type( nombre ) == 'number' then return tostring( nombre ) elseif trim( nombre ) then local result = nombre -- trim :gsub( '^%s*(.*)%f[%s]%s*$', '%1' ) -- remplacement des signes moins ou demi-cadratin par un tiret :gsub( '%−%f[%d]', '-') -- U+2212 :gsub( '−%f[%d]', '-') -- html − :gsub( '\226\128[\146\147]%f[%d]', '-') -- U+2212, U+2213 (tiret numérique et demi-cadratin) -- remplacement des espaces insécable par des espace simple :gsub( '\194\160', ' ' ) result = mw.ustring.gsub( result, '[ - ]', ' ' ) -- U+2002 à U+220A et U+202F return result else return '' end end --- -- parseNum transforme si possible une chaine formatée en un chaine interprétable par tonumber() -- retourne une chaine pour éviter les arrondi éventuels de lua. -- si "nombre" est une chaine non reconnue comme un nombre par la fonction, retourne "nombre". -- si "nombre" n'est pas un number ou une chaine retourne une chaine vide. function p.parseNombre( nombre ) local result if type( nombre ) == 'number' then return tostring( nombre ) else -- remplacement des signes moins ou demi-cadratin par un tiret result = p.sanitizeNum( nombre ) if result == '' then return '' elseif not result:match( '^%-?[%d., ]*%d$' ) then return nombre end end -- suppression espaces result = result:gsub( ' ', '' ) -- gestion des points et des virgules if result:match( '[.,]' ) then if result:match( '%d%.%d%d%d%.%d' ) then -- type 12.345.678 result = result:gsub( '%.', '' ):gsub( ',', '.' ) elseif result:match( '%d,%d%d%d,%d' ) -- type 1,234,567 ou 1.234,567,8 or result:match( '%d,%d%d%d%.%d' ) -- format anglo-saxon type 1,234.5 or result:match( '%d%.%d%d%d,%d' ) -- type 1.123,56 (utilisé en exemple pour sépararer les décimales avec l'ancien modèle unité ou formatnum) then result = result:gsub( ',', '' ) else result = result:gsub( ',', '.' ) end end return result end --- -- _formantNum transforme un nombre ou une chaine représentant un nombre en chaine formatée suivant les conventions du français -- si le paramètre ne représente pas un nombre lua il est retourné sans modification function p.formatNum( num ) local params = {} if type( num ) == 'table' then params = num num = params[1] end if type( num ) == 'number' then num = tostring( num ) elseif type( num ) ~= 'string' or num == '' then return num end -- séparation exposant local n, exponent = num:match( '^([-%d.]+)e([+-]?%d+)$' ) if exponent then num = n if params.noHtml then exponent = exponent:gsub('+?%f[%d]0', '' ) :gsub( '[%d-]', supUnicode ) else exponent = '<sup>' .. exponent:gsub('^%+?(%-?)0?', { ['-'] = '−' } ) .. '</sup>' end exponent = ' ×10' .. exponent else exponent = '' end -- arrondi decimals = tonumber( params.decimals ) round = tonumber( params.round ) or decimals if round then local mult = 10 ^ round num = tostring( math.floor( num * mult + 0.5 ) / mult ) end local moins, entier, fraction = num:match( '^(%-?)(%d*)%.?(%d*)$' ) if not entier then return num end if moins == '-' then moins = '−' -- signe moins (U+2212) end if entier == '' then entier = '0' elseif entier:len() > 3 then local ini = math.fmod( entier:len() - 1, 3 ) + 1 entier = ( entier:sub( 1, ini ) or '') .. entier:sub( ini + 1 ):gsub( '(%d%d%d)', '\194\160%1' ) end if fraction ~= '' or ( decimals and decimals > 0 ) then if decimals and decimals > #fraction then fraction = fraction .. string.rep( '0', decimals - #fraction ) end if #fraction > 4 then fraction = ',' .. fraction:gsub( '(%d%d%d)', '%1\194\160' ):gsub( '\194\160$', '' ) else fraction = ',' .. fraction end end return moins .. entier .. fraction .. exponent end --- -- formatNombre transforme un nombre formaté ou non en chaine formatée suivant les convention du français. -- si la chaine n'est pas reconnu comme un nombre, elle n'est pas modifiée. function p.formatNombre( num, round, decimals ) return p.formatNum{ p.parseNombre( num ), round, decimals } end --- formatNombres transforme tous les nombres d'une chaine en nombre formaté suivant les conventions du français. function p.formatNombres( nombres, round, decimals ) if type( nombres ) == 'number' then return p.formatNum( nombres, round, decimals ) elseif type( nombres ) == 'string' then -- retire les chiffres des strip marker local strip, i = {}, 0 nombres = nombres:gsub( 'UNIQ%-%-%a+%-%x%x%x%x%x%x%x%x%-QINU', function ( marker ) i = i + 1 strip[ tostring( i ) ] = marker return 'UNIQ^' .. i .. '¤QINU' end ) -- formatage proprement dit nombres = p.sanitizeNum( nombres ) nombres = nombres:gsub( '%-?%f[%d.,^][%d., ]+%f[%D]', function ( n ) return p.formatNombre( n, round, decimals ) end ) -- réintroduction des strip marker nombres = nombres:gsub( 'UNIQ^(%d+)¤QINU', strip ) return nombres else return '' end end function p.parseUnit( texte ) local toParse = p.sanitizeNum( texte ) if toParse ~= '' then local result local specificArgs = { ['à'] = 'à', et = 'et', ou = 'ou', ['–'] = '–', -- demi cadratin ['±'] = '±', ['+-'] = '±', ['+/-'] = '±', ['+'] = '+', ['−'] = '−', ['-'] = '−', -- signe moins et tiret ['×'] = '×', x = '×', ['*'] = '×', ['××'] = '××', xx = '××', ['**'] = '××', } -- valeur numérique local match, capture = toParse:match( '^((%-?%f[%d.,][%d., ]*%d%f[%D])%s*)' ) result = { capture or false } if match then toParse = toParse:sub( match:len() + 1 ) -- fraction match, capture = toParse:match( '^(([+-]?%d* ?/ ?%d+)%s*)' ) if not match then match, capture = mw.ustring.match( toParse, '^(([¼-¾⅐-⅞])%s*)' ) end if match then if capture:match( '^/' ) then local n = result[1]:match( ' (%d+)$' ) or '' result[1] = result[1]:sub( 1, -1 - #n ) result.fraction = n .. capture else result.fraction = capture end toParse = toParse:sub( match:len() + 1 ) end -- lien avec un deuxième nombre local match2, conj, num = mw.ustring.match( toParse, '^(([àetouM+/−x*×±–-]+) ?(%-?%f[%d.,][%d., ]*%d%f[%D])%s*)' ) if match2 and specificArgs[ conj ] and not ( specificArgs[ conj ] == '×' and mw.ustring.match( toParse, '^[×x] ?10 ?e') ) then result[ specificArgs[ conj ] ] = num toParse = toParse:sub( match2:len() + 1 ) end if result['+'] or result['×'] then match2, conj, num = mw.ustring.match( toParse, '^(([x*×−-]) ?(%-?%f[%d.,][%d., ]*%d%f[%D])%s*)' ) if match2 then if specificArgs[ conj ] == '×' then result['××'] = num else result['−'] = num end toParse = toParse:sub( match2:len() + 1 ) end end end -- 10 exposant ( \195\151 = ×, signe multiplié) match, capture = toParse:match( '^(%s*e(%-?%d+)%s*)' ) if not match then match, capture = toParse:match( '^(%s*[x\195]\151?10e(%-?%d+)%s*)' ) end if match then result.e = capture toParse = toParse:sub( match:len() + 1 ) end -- unités if Data.unit[ toParse ] or mw.ustring.match( toParse, '^%a+$' ) or toParse:match( '%b<>' ) then table.insert( result, toParse ) toParse = '' elseif toParse ~= '' then local unit, exp toParse = toParse:gsub( '²', '2' ):gsub( '³', '3' ) repeat -- unité contenant un lien match, unit, exp = mw.ustring.match( toParse, '^((/?[^%s%d/%[%]]*%b[][^%s%d/]*) ?(%-?%d*)%s*)' ) if not match then -- unité ne contenant pas de lien match, unit, exp = mw.ustring.match( toParse, '^((/?[^%s%d/]+) ?(%-?%d*)%s*)' ) end if match then if unit:match( '%-$' ) and exp ~= '' then unit = unit:gsub( '%-$', '' ) exp = '-' .. exp elseif exp == '-' then unit = match exp = '' end table.insert( result, unit ) table.insert( result, exp ) toParse = toParse:sub( match:len() + 1 ) end until toParse == '' or not match end if toParse == '' then return result else -- une partie de la chaine n'a pas pu être décodée, on retourne la chaine originale addErrorCat = true return { texte } end else return { } end end --- -- nomUtnit retourne le nom français du code d'une unité et de son exposant. -- si le code de l'unité n'est pas reconnu retourne 1 et false, de façon à ajouter false en première position d'une table. function p.nomUnit( unit, exposant ) if not dataSuccess or type( unit ) ~= 'string' then return 1, false end -- nettoyage des liens et balise HTML unit = unit:gsub( '^/' , '' ) if unit:match( '%[' ) then local Delink = require( 'Module:Delink' ) unit = Delink._delink{ unit } end if unit:match( '<' ) then unit = unit:gsub( '%b<>', '' ) end -- récupère le nom de l'unité local unitTab = Data.unit[ unit ] local unitPrefix = { nom = '' } if not unitTab then unitTab = Data.unit[ unit:sub( 2 ) ] unitPrefix = Data.prefix[ unit:sub( 1, 1 ) ] if not ( unitTab and unitPrefix ) then -- pour µ, Ki, Mi, Gi... qui sont codé sur deux octets unitTab = Data.unit[ unit:sub( 3 ) ] unitPrefix = Data.prefix[ unit:sub( 1, 2 ) ] if not ( unitTab and unitPrefix ) then unitTab = false end end end -- récupère le nom de l'exposant if trim( exposant ) then local exp = tonumber( exposant ) exp = exp and Data.exposant[ math.abs( exp ) ] exposant = exp or ' puissance ' .. exposant else exposant = '' end -- assemble les deux partie if type( unitTab ) == 'table' and type( unitTab.nom ) == 'string' then return unitPrefix.nom .. unitTab.nom .. exposant elseif unit:match( '[/%d]' ) then -- ce n'est pas du texte simple, on anule l'infobule return 1, false else return unit .. exposant end end function p._unite( args ) -- remplacement de certains caractères, pour simplifier les pattern local nombre = p.sanitizeNum( args[1] ) if nombre == '' then nombre = nil else -- formatage du nombre nombre = p.formatNombres( nombre, args.arrondi, args['décimales'] ) end local wiki = { nombre } -- fraction if args.fraction then local nom, den = args.fraction:match( '^(.-)/(.+)$' ) if nom then if nom:match( '^[ %dn()=+-]+$' ) and den:match( '^[ %daeoxhklmnpst()=+-]$' ) then nom = nom:gsub( '[%dn()=+-]', supUnicode ) den = den:gsub( '[%daeoxhklmnpst()=+-]', subUnicode ) else nom = '<sup style="font-size: 70%; vertical-align: 0.4em;">' .. nom .. '</sup>' den = '<sub style="font-size: 70%; vertical-align: 0em;">' .. den .. '</sub>' end args.fraction = nom .. '⁄' .. den end table.insert( wiki, ' ' .. args.fraction ) end -- à, et, ou, ×, – (tiret cadratin) local specificArgs = { '–', 'à', 'et', 'ou', '×', '××', '±' } for _, name in ipairs( specificArgs ) do local v = trim( args[ name ] ) if v then v = p.formatNombres( v ) if name == '–' and nombre and nombre:match( '^[^−]' ) and v:match( '^[^−]' ) then -- pas d'espace pour le tiret cadratin entre deux nombres positifs table.insert( wiki, '–' ) elseif name == '××' then table.insert( wiki, ' × ' ) else table.insert( wiki, ' ' .. name .. ' ' ) end table.insert( wiki, v ) end end -- unités local i = 1 local unit = trim( args[ 2 * i ] ) local units = '' local nomUnits, par = {}, false while unit do local exp = p.parseNombre( args[ 2 * i + 1 ] ) local sep = '' -- gestion des exposants local expUnit = '' if exp == '' then if unit:sub( -2 ) == '²' then exp = '2' unit = unit:sub( 1, -3 ) elseif unit:sub( -2 ) == '³' then exp = '3' unit = unit:sub( 1, -3 ) end end if #exp > 0 then expUnit = '<sup>' .. exp:gsub( '^-', '−') .. '</sup>' -- remplace le tiret par un vrai signe moins end -- gestion de la séparation des unités et des unités en dénominateur if units ~= '' then if unit:sub( 1, 1 ) == '/' then sep = '/' unit = unit:sub( 2 ) if not par then par = true table.insert( nomUnits, 'par' ) end else sep = '\194\160' -- point médian désactivé : '⋅\194\160' if exp:match( '^-' ) and not par then par = true table.insert( nomUnits, 'par' ) end end end -- remplacement de l'unité par son symbole if Data.unit[ unit ] then -- unit = Data.unit[ unit ].symbole -- désactivé car ne gère pas les multiple tel mL end units = units .. sep .. unit .. expUnit table.insert( nomUnits, p.nomUnit( unit, exp ) ) i = i + 1 unit = trim( args[ 2 * i ] ) end -- conversion local unitNameString = nomUnits[1] and table.concat( nomUnits, ' ' ) or '' unitNameString = mw.ustring.gsub( unitNameString, '(%a)s%f[%A]', '%1' ) local multiple = 1 local convertTable = Data.convert[ unitNameString ] if not convertTable and #unitNameString > 5 then -- gesion des multiples (Kilo, méga, mili...) local prefix = Data.prefix[ unitNameString:sub( 1, 4 ) ] or Data.prefix[ unitNameString:sub( 1, 5 ) ] local _, par = unitNameString:find( ' par ' ) local prefix2 if par then prefix2 = Data.prefix[ unitNameString:sub( par + 1, 4 ) ] or Data.prefix[ unitNameString:sub( par + 1, 5 ) ] end if prefix and Data.convert[ unitNameString:gsub( '^' .. prefix.nom, '' ) ] then convertTable = Data.convert[ unitNameString:gsub( '^' .. prefix.nom, '' ) ] multiple = 10 ^ prefix.puissance elseif prefix2 and Data.convert[ unitNameString:gsub( ' par ' .. prefix2.nom, '' ) ] then convertTable = Data.convert[ unitNameString:gsub( ' par ' .. prefix2.nom, '' ) ] multiple = 1 / 10 ^ prefix2.puissance elseif prefix and prefix2 and Data.convert[ unitNameString:gsub( '^' .. prefix.nom, '' ):gsub( ' par ' .. prefix2.nom, '' ) ] then convertTable = Data.convert[ unitNameString:gsub( '^' .. prefix.nom, '' ):gsub( ' par ' .. prefix2.nom, '' ) ] multiple = 10 ^ prefix.puissance / 10 ^ prefix2.puissance end end if convertTable then if type( convertTable[1] ) ~= 'table' then convertTable = { convertTable } end for i, v in ipairs( wiki ) do local n = tonumber( p.parseNombre( v ) ) if n then n = n * 10 ^ ( tonumber( p.parseNombre( args.e ) ) or 0 ) local converted = {} for _, c in ipairs( convertTable ) do local nConverted = n if c.inverse then nConverted = 1 / n end if c.M then -- M = masse molaire local M = tonumber( args.M ) if not M then break end if c.M == '*' then nConverted = nConverted * M elseif c.M == '/' then nConverted = nConverted / M end end nConverted = nConverted * multiple * c[2] + ( c[3] or 0 ) -- format nConverted = p.formatNum{ nConverted, round = c.round or 6, noHtml = true } table.insert( converted, nConverted .. ' '.. c[1] ) end wiki[ i ] = '<span title="' .. table.concat( converted, ' ou ' ) ..'">' .. v ..'</span>' end end end -- incertitude avec + et − séparés if trim( args['+'] ) then local approximation = '+' .. p.formatNombre( args['+'] ) .. '' if trim( args['−'] ) then approximation = approximation .. '<br> −' .. p.formatNombre( args['−'] ) end table.insert( wiki, '<span style="display:inline-block; vertical-align:top; line-height:1em; font-size:80%; text-align:left;">' ) table.insert( wiki, approximation .. '</span>' ) end -- puissance de 10 local exposant = trim( args.e ) if exposant then exposant = p.formatNombre( exposant ) if nombre then if trim( args['±'] ) and not nombre:match( '^%(' ) then table.insert( wiki, 1, '(' ) table.insert( wiki, ')' ) end table.insert( wiki, ' × 10<sup>' .. exposant .. '</sup>' ) else table.insert( wiki, '10<sup>' .. exposant .. '</sup>' ) end end -- ajoute une abbréviation si le nom de l'unité est différent de l'unité (en retirant les espace qui peuvent être devenus insécables) if units and nomUnits[1] and mw.ustring.gsub( table.concat( nomUnits ), '[ \194\160]', '' ) ~= mw.ustring.gsub( units, '[ \194\160]', '' ) then units = string.format( ' <abbr class=abbr title="%s">%s</abbr>', table.concat( nomUnits, ' ' ), units ) elseif units ~= '' and units ~= '°' then units = ' ' .. units end table.insert( wiki, units ) if #wiki > 0 then local result = table.concat( wiki ) if result:match( ' ' ) then return '<span class="nowrap">' .. result .. '</span>' else return result end end end function p.unite( frame ) local args if type( frame ) == 'table' then if type( frame.getParent ) == 'function' then args = frame:getParent().args; else args = frame end end if args then if trim( args[1] ) then if args[1]:match('[^%d,. -]') then local tempArgs = p.parseUnit( trim( args[1] ) ) if not ( args[2] and tempArgs[2] ) then for k, v in pairs( tempArgs ) do args[k] = v end end end if args[2] and not Data.unit[ args[2] ] and not args[3] and mw.text.trim( args[2] ):match('[%d/ -]') then local tempArgs = p.parseUnit( trim( args[2] ) ) args[2] = false if tempArgs[1] ~= false then table.insert( tempArgs, 1, false ) end for k, v in pairs( tempArgs ) do if args[k] and v then addErrorCat = true end args[k] = args[k] or v end end end -- args alias args['x'] = args['×'] -- lettre x → signe multiplié if args['+'] then args['−'] = args['−'] or args['-'] -- tiret → signe moins else args['–'] = args['–'] or args['-'] -- tiret → demi-cadratin end local cat = '' if addErrorCat then cat = errorCat end return p._unite( args ) .. cat end end return p