« Unité » : différence entre les versions
De Wikimanche
wm>Zebulon84 (_unite : implémentation de paramètres de Unité/2) |
wm>Zebulon84 Aucun résumé des modifications |
||
Ligne 27 : | Ligne 27 : | ||
if type( nombre ) == 'number' then | if type( nombre ) == 'number' then | ||
return tostring( nombre ) | return tostring( nombre ) | ||
elseif | elseif trim( nombre ) then | ||
local result = nombre | local result = nombre | ||
-- trim | -- trim | ||
Ligne 361 : | Ligne 361 : | ||
i = i + 1 | i = i + 1 | ||
unit = trim( args[ 2 * i ] ) | unit = trim( args[ 2 * i ] ) | ||
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) | -- 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 | 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 ) | units = string.format( ' <abbr class=abbr title="%s">%s</abbr>', table.concat( nomUnits, ' ' ), units ) | ||
elseif units and units ~= '°' then | |||
units = ' ' .. units | |||
end | end | ||
table.insert( wiki, units ) | 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 | if result:match( ' ' ) then | ||
return '<span class="nowrap">' .. result .. '</span>' | return '<span class="nowrap">' .. result .. '</span>' |
Version du 5 mai 2017 à 18:30
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
--- Copie de Outils.trim acceptant les nombres.
local function trim( texte )
if type( texte ) == 'string' then
texte = texte:gsub( '^%s*(.*)%f[%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', ' ' )
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 )
if type( num ) == 'number' then
num = tostring( num )
elseif type( num ) ~= 'string' or num == '' then
return num
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 ~= '' then
fraction = ',' .. fraction:gsub( '(%d%d%d)', '%1\194\160' ):gsub( '\194\160$', '' )
end
return moins .. entier .. fraction
end
---
-- formatNum transforme les nombres d'une chaine en chaine formatée suivant les conventions du français.
-- Le nombre fourni doit un de type number ou chaine équivalente :
-- pas de séparateur de millier, point comme séparamèteur décimal, tiret comme signe moins.
-- Équivalent de FormatNum, mais avec vrai signe moins et séparateur de millier en partie décimale.
function p.formatNum( num )
if type( num ) == 'number' then
return p._formatNum( num )
elseif type( num ) == 'string' then
return num:gsub( '%-?%d*%.?%d+', p.formatNombre )
else
return ''
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( nombre )
return p._formatNum( p.parseNombre( nombre ) )
end
--- formatNombres transforme tous les nombres d'une chaine en nombre formaté suivant les conventions du français.
function p.formatNombres( texte )
if type( texte ) == 'number' then
return p.formatNum( texte )
elseif type( texte ) == 'string' then
return texte:gsub( '%-?%f[%d.,][%d., ]+%f[%D]', p.formatNombre )
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'] = 'x', x = 'x', ['*'] = 'x',
}
-- valeur numérique
local match, capture = toParse:match( '^((%-?%f[%d.,][%d., \194\160]*%d%f[%D])%s*)' )
if match then
toParse = toParse:sub( match:len() + 1 )
end
result = { capture or false }
-- lien avec un deuxième nombre
local match, conj, num = mw.ustring.match( toParse, '^(([àetouM+/−x*×±–-]+) ?(%-?%f[%d.,][%d., \194\160]*%d%f[%D])%s*)' )
if match and specificArgs( conj ) then
result[ specificArgs[ conj ] ] = num
toParse = toParse:sub( match:len() + 1 )
end
if result['+'] or result['x'] then
match, conj, num = mw.ustring.match( toParse, '^(([x*×−-]) ?(%-?%f[%d.,][%d., \194\160]*%d%f[%D])%s*)' )
if match then
if specificArgs[ conj ] == '×' then
result['xx'] = num
else
result['−'] = num
end
toParse = toParse:sub( match:len() + 1 )
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
toParse = toParse:gsub( '⋅', '.' ):gsub( '²', '2' ):gsub( '³', '3' )
local unit, exp
local unitRegex = '^(%.?(/?[%aà°±]+) ?(%-?%d*)%s*)'
match, unit, exp = mw.ustring.match( toParse, unitRegex )
while match do -- and unit:len() < 5
table.insert( result, unit )
table.insert( result, exp )
toParse = toParse:sub( match:len() + 1 )
match, unit, exp = mw.ustring.match( toParse, unitRegex )
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
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, nbNombre = nombre:gsub( '%-?%f[%d.,][%d., ]+%f[%D]', p.formatNombre )
end
local wiki = { nombre }
-- à, et, ou, ×, – (tiret cadratin)
local specificArgs = { '–', 'à', 'et', 'ou', 'x', 'xx', '±' }
for _, name in ipairs( specificArgs ) do
local v = trim( args[ name ] )
if v then
v = p.sanitizeNum( v ):gsub( '%-?%f[%d.,][%d., ]+%f[%D]', p.formatNombre )
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, '–' .. v )
else
table.insert( wiki, ' ' .. name .. ' ' .. v )
end
end
end
-- incertitude avec + et − séparés
local approximation
if trim( args['+'] ) then
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:-0.4em; line-height:1.2em; font-size:80%; text-align:left;">' )
table.insert( wiki, approximation .. '</span>' )
end
-- puissance de 10
local exposant = trim( args.e )
if exposant then
if nombre then
table.insert( wiki, ' × 10<sup>' .. exposant .. '</sup>' )
else
table.insert( wiki, '10<sup>' .. exposant .. '</sup>' )
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 = ''
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 units ~= '' then
if unit:sub( 1, 1 ) == '/' then
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
local expUnit = ''
if #exp > 0 then
expUnit = '<sup>' .. exp:gsub( '^-', '−') .. '</sup>' -- remplace le tiret par un vrai signe moins
end
units = units .. sep .. unit .. expUnit
table.insert( nomUnits, p.nomUnit( unit, exp ) )
i = i + 1
unit = trim( args[ 2 * i ] )
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 not ( args.e or args.et or args['à'] or args['±'] ) and trim( args[1] ) then
if not args[2] and args[1]:match('[^%d,. -]') then
args = p.parseUnit( trim( args[1] ) )
elseif args[2] and not args[3] and args[2]:match('[%d./ -]') then
local tempArgs = p.parseUnit( trim( args[2] ) )
if tempArgs[1] == false then
tempArgs[1] = args[1]
else
table.insert( tempArgs, 1, args[1] )
end
args = tempArgs
end
end
-- args alias
args['x'] = args['×'] -- lettre x → signe multiplié
if args['+'] then
args['−'] = args['-'] -- tiret → signe moins
else
args['–'] = args['-'] -- tiret → demi-cadratin
end
return p._unite( args )
end
end
return p