Module:Unité
La documentation de ce module Scribunto écrit en Lua est incluse depuis sa sous-page de documentation.
Projet Scribunto : Aide · Catégorie:Modules · Index complet des modules et de leur documentation ·
{{Module|nom du module}}
· {{Modèle utilisant les modules Lua}}
Modules de base :
Documentation module
· String
· List
· Wikibase
· TNT
Utilisation modifier
Fonctions exportables modifier
unite( frame )
– implémente le modèle unité. Les paramètres sont pris soit au niveau du modèle appelant le module via #invoke, soit directement dans la table fournie lorsque la fonction est appelée depuis un autre module. Essaye de parser les deux premiers paramètres pour facilité la saisie (par exemple fonction avecp.unite{ '1.23 ±0.05 e5 m/s-2' }
) ;_unite( args )
– affiche l'unité à partir des paramètres classiques du modèle Unité (exemplep._unite{ '1.23', 'm', '/s', '-2', ['±'] = '0.05', e='5' }
) ;formatNombres( texte )
– formate tous les nombres de la chaine fournie suivant les conventions du français ;formatNombre( nombre )
– transforme un nombre formaté ou non en chaine formatée suivant les conventions du français ; si la chaine n'est pas reconnue comme un nombre, elle n'est pas modifiée ;_formatNum( num )
– transforme un number, ou une chaine correspondant à un number en chaine formatée suivant les conventions du français ; si le paramètre ne représente pas un number lua il est retourné sans modification ;parseNombre( nombre )
– transforme si possible une chaine formatée en un chaine interprétable par tonumber() (retourne une chaine pour éviter les arrondis éventuels de lua) ; les chaines non reconnues sont retournées sans modification.
Autres fonctions modifier
sanitizeNum( nombre )
– transforme les signes moins en tiret, les espaces insécables en espace simple (simplifie les pattern ultérieures) ;parseUnit( texte )
– essaye de séparer une chaine en différents paramètres du modèle unité ;nomUnit( unit, exposant )
– retourne si possible le nom de l'unité et son exposant en toute lettre.
Modules externes et autres éléments dont ce module a besoin pour fonctionner modifier
- Module:Unité/Data – Liste d'unités et de multiples, avec leur abréviation et leur nom en toute lettre.
- Module:Delink – Utilisé pour supprimer les liens des unités pour essayer de les reconnaitre.
Exemples modifier
Pour des exemples, voir la page de test de la Wikipédia en français permettant de tester diverses modifications apportées.
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'] = 'ₜ',
}
local fractionUnicode = { ['½'] = '1/2', ['⅓'] = '1/3', ['⅕'] = '1/5', ['⅙'] = '1/6', ['⅛'] = '1/8',
['⅔'] = '2/3', ['⅖'] = '2/5', ['⅚'] = '5/6', ['⅜'] = '3/8', ['¾'] = '3/4', ['⅗'] = '3/5',
['⅝'] = '5/8', ['⅞'] = '7/8', ['⅘'] = '4/5', ['¼'] = '1/4', ['⅐'] = '1/7', ['⅑'] = '1/9', ['⅒'] = '1/10', ['↉'] = '0/3',
}
local nbsp = '\194\160' -- espace insécable
local nnbsp = '\226\128\175' -- espace fine insécable
--- Copie de Outils.trim acceptant les nombres.
local function trim( texte )
if type( texte ) == 'string' then
-- http://lua-users.org/wiki/StringTrim
texte = texte:match( '^()%s*$' ) and '' or texte:match( '^%s*(.*%S)' )
if texte ~= '' then
return texte
end
elseif type( texte ) == 'number' then
return tostring( texte )
end
end
-- retire les chiffres des strip markers
local function escapeStripMarkers( input )
return input:gsub( '(UNIQ%-%-%a+%-)(%x%x%x%x%x%x%x%x)(%-QINU)', function ( leading, hexdigits, trailing )
local escapeddigits = hexdigits:gsub( '%d', {
['0'] = 'g', ['1'] = 'h', ['2'] = 'i', ['3'] = 'j', ['4'] = 'k',
['5'] = 'l', ['6'] = 'm', ['7'] = 'n', ['8'] = 'o', ['9'] = 'p',
} )
return leading .. escapeddigits .. trailing
end )
end
-- restaure les strip markers
local function restoreStripMarkers( input )
return input:gsub( '(UNIQ%-%-%a+%-)(%a%a%a%a%a%a%a%a)(%-QINU)', function ( leading, escapeddigits, trailing )
local hexdigits = escapeddigits:gsub( '%a', {
['g'] = '0', ['h'] = '1', ['i'] = '2', ['j'] = '3', ['k'] = '4',
['l'] = '5', ['m'] = '6', ['n'] = '7', ['o'] = '8', ['p'] = '9',
} )
return leading .. hexdigits .. trailing
end )
end
-- remplacement de certains caractères, pour simplifier les pattern
function p.sanitizeNum( nombre )
if type( nombre ) == 'number' then
return tostring( nombre )
elseif type( nombre ) == 'string' then
if nombre:match( '^%-?[%d.,]+$' ) then
return nombre
end
local result = nombre
-- remplacement des signes moins par un tiret
:gsub( '%−%f[%d]', '-') -- U+2212
:gsub( '−%f[%d]', '-') -- html −
-- remplacement des espaces insécable par des espace simple
:gsub( nbsp, ' ' )
:gsub( ' ', ' ' )
:gsub( ' ', ' ' )
:gsub( nnbsp, ' ' )
:gsub( ' ', ' ' )
:gsub( ' ', ' ' )
:gsub( '\226\128[\132-\138]', ' ' ) -- U+2004 à U+200A
:gsub( ' ', ' ' )
-- trim
:gsub( '^%s*(%S?.-)%s*$', '%1' )
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 ''
end
-- si nombre est un chiffre en exposant ou indice comme ², retourne ce chiffre
for i = 0, 9 do
local is = tostring(i)
if result == supUnicode[ is ] or result == subUnicode[ is ] then
return is
end
end
if not result:match( '^%-?[%d., ]*%d$' ) and not result:match( '^%-?[%d., ]*%d ?e[+-]?%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
-- Le paramètre peut être transmis sous forme de table pour ajouter des options :
-- * round : arrondi à n chiffre après la virgule (peut être négatif)
-- * decimals : nombre de décimales affichées (peut être négatif, dans ce cas équivalent à round)
-- * noHtml : n'utilise pas de balise HTML pour affiché les puissance de 10 (pour pouvoir être utilisé en title)
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.]+)[eE]([+-]?%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
if num == '1' then
return '10' .. exponent
end
exponent = nbsp .. '×' .. nnbsp .. '10' .. exponent
else
exponent = ''
end
-- arrondi
local decimals = tonumber( params.decimals )
local round = tonumber( params.round ) or decimals
if round and tonumber( num ) then
local mult = 10 ^ round
num = tostring( math.floor( num * mult + 0.5 ) / mult )
end
local moins, entier, deci = 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)', nbsp .. '%1' )
end
if deci ~= '' or ( decimals and decimals > 0 ) then
if decimals and decimals > #deci then
deci = deci .. string.rep( '0', decimals - #deci )
end
if #deci > 3 then
deci = ',' .. deci:gsub( '(%d%d%d)', '%1' .. nbsp ):gsub( nbsp .. '$', '' )
else
deci = ',' .. deci
end
end
return moins .. entier .. deci .. 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 = round, decimals = 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 = round, decimals = decimals }
elseif type( nombres ) == 'string' then
-- retire les chiffres des strip markers
nombres = escapeStripMarkers( nombres )
-- formatage proprement dit
nombres = p.sanitizeNum( nombres )
local formatN = function ( n )
return p.formatNombre( n, round, decimals )
end
if nombres:match('%d%-%d') then
nombres = nombres:gsub( '%f[%d.,][%d., ]*%d', formatN )
else
nombres = nombres
:gsub( '%-?%f[%d.,][%d., ]*%d ?e[+-]?%d+', formatN )
:gsub( '%-?%f[%d.,][%d., ]*%d', formatN )
end
-- restaure les strip markers
nombres = restoreStripMarkers( nombres )
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, cadratin et tiret
['±'] = '±', ['+-'] = '±', ['+/-'] = '±',
['+'] = '+',
['−'] = '−', -- signe moins
['×'] = '×', x = '×', ['*'] = '×',
['××'] = '××', xx = '××', ['**'] = '××',
}
-- valeur numérique
local cap0, capture = toParse:match( '^(([%d., ]+%f[^d%(])%s*)' )
local prefix
if not cap0 then
-- cas d'un nombre entre guillemet, gras, italique...
cap0, capture = toParse:match( '^((["\']+[%d., ]+["\']+)%s*)' )
end
if not cap0 then
-- cas ou le nombre est remplcé par un ou plusieurs points d'interrogation
cap0, prefix = toParse:match( '^((%?+)%s*)' )
end
if not cap0 then
-- cas ou un mot type "vers", "environ" précède le nombre (mot simple, sans accent pour ne pas complexifier pour des cas minoritaires)
cap0, prefix, capture = toParse:match( '^(([%a ]+[.,]?[: ]* )([+-]? ?%f[%d.,][%d., ]*%d%f[%D])%s*)' )
end
if not cap0 then
-- cas ou le nombre est précédé par un signe, un symbole ASCII, ou suivit d'une incerititude entre parenthèse
cap0, prefix, capture = toParse:match( '^(([(<>=~ ]*)([+-]? ?%f[%d.,][%d., ]*%d%(?[%d%.]*%)?)%s*)' )
end
if not cap0 then
-- cas ou le nombre est précédé par un symbole ≤, ≥, ≈, ≃ et quelque autres
cap0, prefix, capture = toParse:match( '^((\226[\136\137][\131\136\164\165\187\188] ?)([+-]?%f[%d.,][%d., ]*%d%f[%D])%s*)' )
end
if not cap0 then
-- cas ou le nombre est précédé par un symbole ± (\194\177)
cap0, prefix, capture = toParse:match( '^((±) ?(%f[%d.,][%d., ]*%d%f[%D])%s*)' )
end
result = { capture or false, prefix = prefix }
if cap0 then
toParse = toParse:sub( cap0:len() + 1 )
-- point de suspensions (ex π = 3.14159...)
cap0 = toParse:match( '^…%s*' )
if not cap0 then
cap0 = toParse:match( '^%.%.%.%s*' )
end
if cap0 then
result[1] = result[1] .. '…'
toParse = toParse:sub( cap0:len() + 1 )
end
if toParse == '' then
return result
end
end
-- fraction
capture = mw.ustring.sub( toParse, 1, 1 )
if fractionUnicode[ capture ] then
result.fraction = fractionUnicode[ capture ]
toParse = toParse:sub( capture:len() + 1 ):gsub( '^%s*', '' )
result[1] = result[1] or ''
else
cap0, capture = toParse:match( '^(([%d,]*/%f[%d][%d ]*%d)%s*)' )
if not cap0 then
-- caractère de fraction ⁄ = \226\129\132
cap0, capture = toParse:match( '^((%d*⁄%d+)%s*)' )
if cap0 then
capture = capture:gsub( '⁄', '/' )
end
end
if cap0 then
if result[1] and capture:match( '^/' ) then
local n = result[1]:match( ' %d+$' ) or result[1]:match( '^%d+$' ) or ''
result[1] = result[1]:sub( 1, -1 - #n )
result.fraction = n:gsub( '^ ', '' ) .. capture
else
result.fraction = capture
end
toParse = toParse:sub( cap0:len() + 1 )
end
end
if toParse~= '' and ( result[1] or result.fraction ) then
-- lien avec un deuxième nombre
local cap0, conj, num = toParse:match( '^(([etou+/;x*-]+) *(%-?%f[%d.,][%d., ]*%d%f[%D]%)?)%s*)' )
if not cap0 and toParse:byte() > 127 then
cap0, conj, num = mw.ustring.match( toParse, '^(([à−×±—–]+) *(%-?%f[%d.,][%d., ]*%d%f[%D]%)?)%s*)' )
end
if cap0 and specificArgs[ conj ]
and not (
specificArgs[ conj ] == '×'
and (
mw.ustring.match( toParse, '^[×x] ?10 ?e' )
or mw.ustring.match( toParse, '^[×x] ?10<sup>(%-?%d+)</sup>' )
)
)
then
result[ specificArgs[ conj ] ] = num
toParse = toParse:sub( cap0:len() + 1 )
end
if result['+'] or result['×'] or result['/'] then
cap0, conj, num = mw.ustring.match( toParse, '^(([/;x*×−-]) *(%-?%f[%d.,][%d., ]*%d%f[%D])%s*)' )
if cap0 then
if specificArgs[ conj ] == '×' then
result['××'] = num
elseif specificArgs[ conj ] == '/' then
result['//'] = num
else
result['−'] = num
end
toParse = toParse:sub( cap0:len() + 1 )
end
end
end
-- 10 exposant ( \195\151 = ×, signe multiplié)
cap0, capture = toParse:match( '^(e(%-?%d+)%s*)' )
if not cap0 then
cap0, capture = toParse:match( '^([x\195]\151? ?10e(%-?%d+)%s*)' )
end
if not cap0 then
cap0, capture = toParse:match( '^([x\195]\151? ?10<sup>(%-?%d+)</sup>%s*)' )
end
if cap0 then
result.e = capture
toParse = toParse:sub( cap0:len() + 1 )
end
if result[1] == '10' and not result.e and not result.fraction then
cap0, capture = toParse:match( '^(<sup>(%-?%d+)</sup>%s*)' )
if cap0 then
result[1] = false
result.e = capture
toParse = toParse:sub( cap0:len() + 1 )
end
end
if toParse == '' then
return result
end
-- unités
local texteUnit = toParse
toParse = toParse:gsub( '^([^%[<]-)<sup>(%d)</sup>', '%1%2' )
if Data.unit[ toParse ]
or toParse:match( '%b<>' )
or toParse:match( 'UNIQ%-%-%a+%-%x%x%x%x%x%x%x%x%-QINU' )
or mw.ustring.match( toParse, '^%a+$' )
then
result[ #result + 1] = toParse
toParse = ''
elseif toParse:match( '%b<>' ) then
toParse = toParse:gsub( '²', '2' ):gsub( '³', '3' )
end
if toParse ~= '' then
local unit, exp
toParse = toParse:gsub( '²', '2' ):gsub( '³', '3' )
repeat
-- unité contenant un lien
cap0, unit, exp = mw.ustring.match( toParse, '^((/? ?[^%s%d/%[%]]*%b[][^%s%d/]*) ?(%-?%d*)%s*)' )
if not cap0 then
-- unité ne contenant pas de lien
cap0, unit, exp = mw.ustring.match( toParse, '^((/? ?[^%s%d/]+) ?(%-?%d*)%s*)' )
end
if not cap0 then
-- l/100 km
cap0, unit, exp = mw.ustring.match( toParse, '^((/100 ?[^%s%d/]+) ?(%-?%d*)%s*)' )
end
if cap0 then
if unit:match( '%-$' ) and exp ~= '' then -- rustine pour quand le "-" se retrouve dans la capture "unit" au lieu de la capture "exp"
unit = unit:gsub( '%-$', '' )
exp = '-' .. exp
elseif exp == '-' then -- rustine pour quand un "-" a été capturé dans "exp" mais sans qu'il y ait de chiffres après
unit = cap0
exp = ''
end
if Data.unit[ unit ] or mw.ustring.match( unit, '[%a€£$¥«»]' ) then
result[ #result + 1] = unit
result[ #result + 1] = exp
toParse = toParse:sub( cap0:len() + 1 )
else
break
end
end
until toParse == '' or not cap0
end
if toParse == '' then
if #result > 3 then
local estSimpleTexte = true
for r = 2, #result, 2 do
if Data.unit[ result[ r ] ]
or result[ r ]:sub( 1, 1 ) == '/'
or Data.prefix[ result[ r ]:sub( 1, 1 ) ] and Data.unit[ result[ r ]:sub( 2 ) ]
or Data.prefix[ result[ r ]:sub( 1, 2 ) ] and Data.unit[ result[ r ]:sub( 3 ) ]
or result[ r + 1 ] and result[ r + 1 ] ~= ''
then
estSimpleTexte = false
break
end
end
if estSimpleTexte then
result[ 2 ] = texteUnit
for r = #result, 3, -1 do
result[ r ] = nil
end
end
end
if #result > 1 and result[ #result ] == '' then
result[ #result ] = nil
end
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
---
-- nomUnit 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 false.
function p.nomUnit( unit, exposant )
unit = trim( unit )
if not dataSuccess or type( unit ) ~= 'string' then
return 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
-- /100
local divisor = ''
if unit:sub( 1, 2 ) == '10' then
divisor, unit = unit:match( '^(1[0 ]*)(.+)$' )
local divisorName = {
['10'] = 'dix ',
['100'] = 'cent ',
['1000'] = 'mille ',
['10000'] = 'dix-mille ',
['100000'] = 'cent-mille ',
['1000000'] = 'un million de ',
['1000000000'] = 'un millard de ',
}
divisor = divisorName[ divisor:gsub( ' ', '' ) ]
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 divisor .. unitPrefix.nom .. unitTab.nom .. exposant
elseif unit:match( '[/%d]' ) then
-- ce n'est pas du texte simple, on anule l'infobule
return false
else
return unit .. exposant
end
end
function p._unite( args )
-- formatage du nombre
local nombre = p.formatNombres( args[1], args.arrondi, args['décimales'] )
if nombre == '' then
nombre = nil
end
local wiki = {}
-- prefix est un paramètre interne défini par p.parseUnit, utile notamment lorsque {{unité}} est utilisé dans les infobox
if args.prefix then
wiki[ #wiki + 1 ] = args.prefix
end
if nombre then
wiki[ #wiki + 1 ] = nombre
end
-- fraction
local fraction = args.fraction
if fraction then
fraction = fractionUnicode[ fraction ] or fraction
local nom, den = fraction:match( '^(.-)/(.+)$' )
if nom then
if nom:match( '^[%dn]%d?$' ) 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;">'
.. p.formatNombres( nom )
.. '</sup>'
den = '<sub style="font-size: 70%; vertical-align: 0em;">'
.. p.formatNombres( den )
.. '</sub>'
end
fraction = nom .. '⁄' .. den
end
if nombre then
wiki[ #wiki + 1 ] = nbsp
end
wiki[ #wiki + 1 ] = fraction
end
-- à, et, ou, ×, – (tiret cadratin)
local specificArgs = { '–', 'à', 'et', 'ou', '/', '//', '×', '××', '±' }
for i = 1, #specificArgs do
local name = specificArgs[ i ]
local v = args[ name ] and trim( args[ name ] )
if v then
v = p.formatNombres( v )
if name == '//' then
name = '/'
elseif name == '××' then
name = '×'
end
if name == '–' and nombre and nombre:match( '^[^−]' ) and v:match( '^[^−]' ) then
-- pas d'espace pour le tiret cadratin entre deux nombres positifs
wiki[ #wiki + 1 ] = '–'
elseif name == '×' or name == '±' then
wiki[ #wiki + 1 ] = nbsp .. name .. nbsp
else
wiki[ #wiki + 1 ] = nbsp .. name .. ' '
end
wiki[ #wiki + 1 ] = v
end
end
-- analyse de l'unité pour la conversion (mais ne sera affiché qu'après l'incertitude + et - séparé)
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
local suffix = unit:sub( -2 ) -- yes, it's 2 bytes
if suffix == '²' then
exp = '2'
unit = unit:sub( 1, -3 )
elseif suffix == '³' 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 unit:sub( 1, 1 ) == '/' then
sep = '/'
unit = trim( unit:sub( 2 ) ) or ''
if not par then
par = true
if unit:sub( 1, 2 ) == '10' then
nomUnits[ #nomUnits + 1 ] = 'pour'
else
nomUnits[ #nomUnits + 1 ] = 'par'
end
else
nomUnits[ #nomUnits + 1 ] = 'et par'
if nomUnits[ #nomUnits - 2 ] == 'et par' then
nomUnits[ #nomUnits - 2 ] = 'par'
end
end
elseif units ~= '' then
sep = nbsp
end
if exp:match( '^-' ) and not par then
par = true
nomUnits[ #nomUnits + 1 ] = 'par'
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
local nomUnit = p.nomUnit( unit, exp )
if nomUnit then
nomUnits[ #nomUnits + 1 ] = nomUnit
else
-- si le code de l'unité n'est pas reconnu, insère false en première position de la table.
table.insert( nomUnits, 1, false )
end
i = i + 1
unit = trim( args[ 2 * i ] )
end
local unitFullName = nomUnits[1] and table.concat( nomUnits, ' ' ) or false
-- conversion
if unitFullName then
local nameSingular = mw.ustring.gsub( unitFullName, '(%a)s%f[%A]', '%1' )
local multiple = 1
local convertTable = Data.convert[ nameSingular ]
if not convertTable and #nameSingular > 5 then
-- gesion des multiples (Kilo, méga, mili...)
local prefix = Data.prefix[ nameSingular:sub( 1, 4 ) ] or Data.prefix[ nameSingular:sub( 1, 5 ) ]
local _, par = nameSingular:find( ' par ' )
local prefix2
if par then
prefix2 = Data.prefix[ nameSingular:sub( par + 1, 4 ) ] or Data.prefix[ nameSingular:sub( par + 1, 5 ) ]
end
if prefix and Data.convert[ nameSingular:gsub( '^' .. prefix.nom, '' ) ] then
convertTable = Data.convert[ nameSingular:gsub( '^' .. prefix.nom, '' ) ]
multiple = 10 ^ prefix.puissance
elseif prefix2 and Data.convert[ nameSingular:gsub( ' par ' .. prefix2.nom, '' ) ] then
convertTable = Data.convert[ nameSingular:gsub( ' par ' .. prefix2.nom, '' ) ]
multiple = 1 / 10 ^ prefix2.puissance
elseif prefix and prefix2 and Data.convert[ nameSingular:gsub( '^' .. prefix.nom, '' ):gsub( ' par ' .. prefix2.nom, '' ) ] then
convertTable = Data.convert[ nameSingular: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 = 1, #wiki do
local v = wiki[ i ]
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 }
local sep = ' '
if c[1]:sub( 1, 2 ) == '°' then -- yes, it's 2 bytes
sep = ''
end
converted[ #converted + 1 ] = nConverted .. sep.. c[1]
end
wiki[ i ] = '<span title="' .. table.concat( converted, ' ou ' ) ..'">' .. v ..'</span>'
end
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
wiki[ #wiki + 1 ] = '<span class="nowrap"><span style="display:inline-block; padding-left:0.2em; vertical-align:top; line-height:1em; font-size:80%; text-align:left;">'
wiki[ #wiki + 1 ] = approximation .. '</span></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, '(' )
wiki[ #wiki + 1 ] = ')'
end
wiki[ #wiki + 1 ] = nbsp .. '×' .. nnbsp .. '10<sup>' .. exposant .. '</sup>'
else
wiki[ #wiki + 1 ] = '10<sup>' .. exposant .. '</sup>'
end
end
if units ~= '' then
local sep = nbsp
if not ( nombre or args.fraction or exposant ) then
sep = ''
else
local symbole = Data.unit[ units ] and Data.unit[ units ].symbole
if symbole == '°' or symbole == '′' or symbole == '″' then
sep = ''
end
end
-- ajoute une abréviation si le nom de l'unité est différent de l'unité (en considérant les espaces qui peuvent être devenus insécables)
if unitFullName and unitFullName ~= units:gsub( nbsp, ' ' ) then
units = string.format( '<abbr class="abbr" title="%s">%s</abbr>', unitFullName, units )
end
wiki[ #wiki + 1 ] = sep .. units
end
if #wiki > 0 then
return table.concat( wiki )
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
addErrorCat = false
args[1] = trim( args[1] ) or false
local basique = require( 'Module:Yesno' )( args.basique )
if args[1] and not basique then
if args[1]:match('[^%d,. -]') then
local tempArgs = p.parseUnit( args[1] )
if not ( args[2] and tempArgs[2] ) then
for k, v in pairs( tempArgs ) do
args[k] = v
end
end
end
args[2] = trim( args[2] ) or false
if args[2] and not args[3] then
-- cas ou le paramètre 2 contient 'm3' ou 'km2'
local a, d = args[2]:match('^(%a%a?)(%d)$')
if a and Data.unit[a] then
args[2] = a
args[3] = d
end
-- cas ou le paramètre 2 contient 'km/s' ou 'm3/h'
if args[2]:match('/') then
local tempArgs = p.parseUnit( 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
end
-- args alias
args['×'] = args['×'] or args['x'] -- lettre x → signe multiplié
args['±'] = args['±'] or args['+-'] or args['+/-']
if args['+'] then
args['−'] = args['−'] or args['-'] -- tiret → signe moins
else
args['–'] = args['–'] or args['-'] -- tiret → demi-cadratin
end
local cat = ''
if addErrorCat and mw.title.getCurrentTitle():inNamespaces( 0, 4, 8, 10, 12, 14, 100, 828 ) then
cat = errorCat
mw.log( errorCat ,' → ', args[1], '|', args[2] )
end
return ( p._unite( args ) or '' ) .. cat
end
end
function p.emulationFormatnum( frame )
local args = frame:getParent().args
return p.formatNombres( args[1] )
end
return p