Module:Unité : Différence entre versions

De Lagny-sur-Marne Wiki
Aller à : navigation, rechercher
(retouche de la modification précédente)
(ajoute des infobulles avec le nom de l'unité.)
Ligne 1 : Ligne 1 :
local p = { }
+
local p = {}
 +
 
 +
-- 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.
 
--- Copie de Outils.trim acceptant les nombres.
Ligne 10 : Ligne 19 :
 
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 type( nombre ) == 'string' 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
 
end
 
end
  
 
---
 
---
-- parseNum transforme si possible une chaine formater en un chaine interprétable par tonumber()
+
-- 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 nombre ou une chaine retourne une chaine vide.
+
-- 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
nombre = tostring( nombre )
+
return tostring( nombre )
elseif type( nombre ) ~= 'string' then
+
else
return ''
+
-- 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
 
 
-- remplacement des signes moins ou demi-cadratin par un tiret
+
-- suppression espaces
nombre = nombre:gsub( '^&minus', '-' )
+
result = result:gsub( ' ', '' )
:gsub( '^\226\128[\146\147]', '-' ) -- U+2012, U+2013 (voir [[Tiret]])
 
:gsub( '^\226\136\147', '-' ) -- U+2212
 
 
 
if nombre:match( '^%-?[%d., \194\160]*%d$' ) then
+
if result:match( '[.,]' ) then
-- suppression espaces et espaces insécables
+
if result:match( '%d+,%d%d%d,%d%d%d%f[%D]' ) -- type 1,234,567  
nombre = nombre:gsub( ' ', '' ):gsub( '\194\160', '' )
+
or result:match( '%d+,%d%d%d%.%d+' )  -- type 1,234.5
+
--or nombre:match( '%d+,%d00$' )  -- type 1,200
if nombre:match( '[.,]' ) then
+
then
if nombre:match( '%d+,%d%d%d,%d%d%d%f[%D]' ) -- type 1,234,567  
+
-- format anglo-saxon
or nombre:match( '%d+,%d%d%d%.%d+' )  -- type 1,234.5
+
result = result:gsub( ',', '' )
--or nombre:match( '%d+,%d00$' )  -- type 1,200
+
elseif result:match( '%d+%.%d%d%d,%d' ) or result:match( '%d+%.%d%d%d%.%d%d%d%f[%D]' ) then
then
+
-- formant germanique type 1.234,5
-- format anglo-saxon
+
result = result:gsub( '%.', '' ):gsub( ',', '.' )
nombre = nombre:gsub( ',', '' )
+
else
elseif nombre:match( '%d+%.%d%d%d,%d' ) or nombre:match( '%d+%.%d%d%d%.%d%d%d%f[%D]' ) then
+
result = result:gsub( ',', '.' )
-- formant germanique type 1.234,5
 
nombre = nombre:gsub( '%.', '' ):gsub( ',', '.' )
 
else
 
nombre = nombre:gsub( ',', '.' )
 
end
 
 
end
 
end
 
end
 
end
 
 
return nombre
+
return result
 
end
 
end
  
Ligne 59 : Ligne 87 :
 
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+)%.?(%d*)$' )
+
local moins, entier, fraction = num:match( '^(%-?)(%d*)%.?(%d*)$' )
 
if not entier then
 
if not entier then
 
return num
 
return num
Ligne 72 : Ligne 100 :
 
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
Ligne 84 : Ligne 114 :
  
 
---
 
---
-- formatNum transforme les nombres d'une chaine en chaine formatée suivant les conventions du français
+
-- 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 )
 
function p.formatNum( num )
 
if type( num ) == 'number' then
 
if type( num ) == 'number' then
Ligne 90 : Ligne 123 :
 
elseif type( num ) == 'string' then
 
elseif type( num ) == 'string' then
 
return num:gsub( '%-?%d*%.?%d+', p.formatNombre )
 
return num:gsub( '%-?%d*%.?%d+', p.formatNombre )
 +
else
 +
return ''
 
end
 
end
 
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 )
 
function p.formatNombre( nombre )
 
return p._formatNum( p.parseNombre( 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
 
end
  
 
function p.parseUnit( texte )
 
function p.parseUnit( texte )
if trim( texte ) then
+
local toParse = p.sanitizeNum( texte )
local toParse = texte
+
if toParse ~= '' then
 
local result
 
local result
 +
local specificArgs = { ['à'] = 'à', et = 'et', ['–'] = '–', ['±'] = '±' }
 +
 
-- valeur numérique
 
-- valeur numérique
local nombre = toParse:match( '^%-?%f[%d][%d., \194\160]*%d%f[%D]' ) or false
+
local match, capture = toParse:match( '^((%-?%f[%d.,][%d., \194\160]*%d%f[%D])%s*)' )
if nombre then
+
if match then
toParse = toParse:sub( nombre:len() + 1 )
+
toParse = toParse:sub( match:len() + 1 )
 
end
 
end
result = { nombre }
+
result = { capture or false }
 
 
 
-- 10 exposant  ( \195\151 = ×, signe multiplié)
 
-- 10 exposant  ( \195\151 = ×, signe multiplié)
local match, e = toParse:match( '^(%s*[x\195]\151?10e(%-?%d+))' )
+
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
table.insert( result, 'e' )
+
result.e = capture
table.insert( result, e )
 
 
toParse = toParse:sub( match:len() + 1 )
 
toParse = toParse:sub( match:len() + 1 )
 
end
 
end
Ligne 118 : Ligne 171 :
 
-- unités
 
-- unités
 
toParse = toParse:gsub( '⋅', '.' )
 
toParse = toParse:gsub( '⋅', '.' )
local match, unit, exp = mw.ustring.match( toParse, '^(%s*%.?([%a°/]+)(%-?%d*))' )
+
local unit, exp
 +
local unitRegex = '^(%.?(/?[%aà°±]+) ?(%-?[%d%.,]*)%s*)'
 +
match, unit, exp = mw.ustring.match( toParse, unitRegex )
 
while match and unit:len() < 5 do
 
while match and unit:len() < 5 do
table.insert( result, unit )
+
if specificArgs[ unit ] then
table.insert( result, exp )
+
result[ specificArgs[ unit ] ] = exp
 +
else
 +
table.insert( result, unit )
 +
table.insert( result, exp )
 +
end
 
toParse = toParse:sub( match:len() + 1 )
 
toParse = toParse:sub( match:len() + 1 )
match, unit, exp = mw.ustring.match( toParse, '^(%s*%.?([%a°/]+)(%-?%d*))' )
+
match, unit, exp = mw.ustring.match( toParse, unitRegex )
 
end
 
end
if trim( toParse ) then
+
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
 
return { texte }
 
return { texte }
else
+
end
return result
 
end  
 
 
else
 
else
 
return { }
 
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, exp )
 +
if not dataSuccess or type( unit ) ~= 'string' then
 +
return 1, false
 +
end
 +
unit = unit:gsub( '^/' , '' )
 +
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
 +
unitTab = Data.unit[ unit:sub( 3 ) ]
 +
unitPrefix = Data.prefix[ unit:sub( 1, 2 ) ]
 +
if not ( unitTab and unitPrefix ) then
 +
unitTab = false
 +
end
 +
end
 +
end
 +
if type( unitTab ) == 'table' and type( unitTab.nom ) == 'string' then
 +
exp = tonumber( exp )
 +
exp = exp and math.abs( exp )
 +
local exposant = exp and Data.exposant[exp] or ''
 +
return unitPrefix.nom .. unitTab.nom .. exposant
 +
else
 +
return 1, false
 
end
 
end
 
end
 
end
  
 
function p._unite( args )
 
function p._unite( args )
local wiki = { }
 
 
local sep = ''
 
local sep = ''
local nombre = trim( args[1] )
+
local nombre, nbNombre, nombre2, nbNombre2
local unit = trim( args[2] )
 
local exp = trim( args.e )
 
 
 
if nombre then
+
nombre = p.sanitizeNum( args[1] )
nombre = nombre
+
if nombre == '' then
-- remplacement des signes moins par des tirets pour facilité les traitements ultérieurs
+
nombre = nil
:gsub( '%%f[%d]', '-')  -- U+2212
+
else
:gsub( '&minus;%f[%d]', '-')  -- html &minus;
+
-- formatage du nombre
:gsub( '\226\128[\146\147]%f[%d]', '-') -- U+2212, U+2213 (tiret numérique et demi-cadratin)
+
nombre, nbNombre = nombre:gsub( '%-?%f[%d.,][%d., ]+%f[%D]', p.formatNombre )
-- remplacement des espaces insécable par des espace simple
 
:gsub( '\194\160', ' ' )
 
 
end
 
end
+
if nombre and not unit and not exp and nombre:match('[^%d,. -]') then
+
-- et / à '–'
args = p.parseUnit( nombre )
+
local intervalle = trim( args.et ) and ' et '
nombre = args[1]
+
or trim( args['à'] ) and ' à '
unit = args[2]
+
or args['–'] and '–'
 +
if nombre and intervalle then
 +
nombre2 = nombre2 or trim( args['à'] ) or trim( args.et ) or trim( args['–'] )
 +
if nombre2 then
 +
nombre2 = p.sanitizeNum( nombre2 )
 +
nombre2, nbNombre2 = nombre2:gsub( '%-?%f[%d.,][%d., ]+%f[%D]', p.formatNombre )
 +
if intervalle == '–' and nombre:sub( 1, 2 ) == '−' then
 +
intervalle = ' – '
 +
end
 +
end
 
end
 
end
 
 
-- formatage du nombre
+
-- ±
if nombre then
+
local approximation
nombre = nombre:gsub( '%-?%f[%d][%d., ]+%f[%D]', p.formatNombre )
+
if trim( args['±'] ) then
table.insert( wiki, nombre )
+
approximation = '±\194\160' .. p.formatNombre( args['±'] )
sep = ' '
 
 
end
 
end
 
 
 
-- puissance de 10
 
-- puissance de 10
local i = 1
+
local exposant = trim( args.e )
if not exp and unit == '10' or unit == 'e' then
+
if exposant then
exp = args[3]
+
if nombre then
i = 2
+
exposant = '×\194\16010<sup>' .. exposant .. '</sup>'
unit = trim( args[4] )
 
end
 
if exp then
 
if #wiki > 0 then
 
table.insert( wiki, '\194\160×\194\16010<sup>' .. exp .. '</sup>' )
 
 
else
 
else
table.insert( wiki, '10<sup>' .. exp .. '</sup>' )
+
exposant = '10<sup>' .. exposant .. '</sup>'
 
end
 
end
sep = ' '
 
 
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 unit == '°' then
+
local exp = tonumber( p.parseNombre( args[ 2 * i + 1 ] ) )
sep = ''
+
local sep = ''
end
+
if units ~= '' then
table.insert( wiki, sep )
+
if unit:sub( 1, 1 ) == '/' then
table.insert( wiki, unit )
+
if not par then
exp = trim( args[ 2 * i + 1 ] )
+
par = true
if exp then
+
table.insert( nomUnits, 'par' )
table.insert( wiki, '<sup>' .. exp:gsub( '%-', '−' ) .. '</sup>' )
+
end
 +
else
 +
sep = '\194\160'  -- point médian désactivé : '⋅\194\160' 
 +
if exp and not par and exp < 0 then
 +
par = true
 +
table.insert( nomUnits, 'par' )
 +
end
 +
end
 
end
 
end
 +
local expUnit = exp and '<sup>' .. exp .. '</sup>' or ''
 +
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 ] )
sep = '\194\160⋅\194\160'
 
 
end
 
end
 +
 +
if units == '°' then
 +
nombre = nombre and nombre .. '°'
 +
nombre2 = nombre2 and nombre2 .. '°'
 +
approximation = approximation and approximation .. '°'
 +
units = nil
 +
end
 +
if intervalle then
 +
nombre = nombre .. intervalle .. nombre2
 +
end
 +
 +
local wiki = { nombre }
 +
table.insert( wiki, approximation )
 +
table.insert( wiki, exposant )
 +
if nomUnits[1] then
 +
units = string.format( '<abbr class=abbr title="%s">%s</abbr>', table.concat( nomUnits, ' ' ), units )
 +
end
 +
table.insert( wiki, units )
 
 
 
if #wiki > 0 then
 
if #wiki > 0 then
local result = table.concat( wiki ):gsub( '\194\160⋅\194\160/', '/' ) -- nettoyage cas particulier de parseunit.
+
local result = table.concat( wiki, ' ' )
return '<span class="nowrap">' .. result .. '</span>'
+
if result:match( ' ' ) then
 +
return '<span class="nowrap">' .. result .. '</span>'
 +
else
 +
return result
 +
end
 
end
 
end
 
end
 
end
Ligne 210 : Ligne 332 :
 
end
 
end
 
if args then
 
if args then
 +
if #args == 1
 +
and not ( args.e or args.et or args['à'] or args['±'] )
 +
and trim( args[1] )
 +
and args[1]:match('[^%d,. -]')
 +
then
 +
args = p.parseUnit( trim( args[1] ) )
 +
end
 
return p._unite( args )
 
return p._unite( args )
 
end
 
end

Version du 30 avril 2015 à 14:25

La documentation pour ce module peut être créée à Module:Unité/doc

local p = {}

-- 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 type( nombre ) == 'string' 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( '&minus;%f[%d]', '-')  -- html &minus;
			: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( ' ', '' )
	
	if result:match( '[.,]' ) then
		if result:match( '%d+,%d%d%d,%d%d%d%f[%D]' ) -- type 1,234,567 
			or result:match( '%d+,%d%d%d%.%d+' )  -- type 1,234.5
			--or nombre:match( '%d+,%d00$' )  -- type 1,200
		then
			-- format anglo-saxon
			result = result:gsub( ',', '' )
		elseif result:match( '%d+%.%d%d%d,%d' ) or result:match( '%d+%.%d%d%d%.%d%d%d%f[%D]' ) then
			-- formant germanique type 1.234,5
			result = result:gsub( '%.', '' ):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', ['–'] = '–', ['±'] = '±' }
		
		-- 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 }
		
		-- 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( '⋅', '.' )
		local unit, exp
		local unitRegex = '^(%.?(/?[%aà°±]+) ?(%-?[%d%.,]*)%s*)'
		match, unit, exp = mw.ustring.match( toParse, unitRegex )
		while match and unit:len() < 5 do
			if specificArgs[ unit ] then
				result[ specificArgs[ unit ] ] = exp
			else
				table.insert( result, unit )
				table.insert( result, exp )
			end
			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, exp )
	if not dataSuccess or type( unit ) ~= 'string' then
		return 1, false
	end
	unit = unit:gsub( '^/' , '' )
	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
			unitTab = Data.unit[ unit:sub( 3 ) ]
			unitPrefix = Data.prefix[ unit:sub( 1, 2 ) ]
			if not ( unitTab and unitPrefix ) then
				unitTab = false
			end
		end
	end
	if type( unitTab ) == 'table' and type( unitTab.nom ) == 'string' then
		exp = tonumber( exp )
		exp = exp and math.abs( exp )
		local exposant = exp and Data.exposant[exp] or ''
		return unitPrefix.nom .. unitTab.nom .. exposant 
	else
		return 1, false
	end
end

function p._unite( args )
	local sep = ''
	local nombre, nbNombre, nombre2, nbNombre2
	
	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
		
	-- et / à '–'
	local intervalle = trim( args.et ) and ' et ' 
		or trim( args['à'] ) and ' à ' 
		or args['–'] and '–'
	if nombre and intervalle then
		nombre2 = nombre2 or trim( args['à'] ) or trim( args.et ) or trim( args['–'] )
		if nombre2 then 
			nombre2 = p.sanitizeNum( nombre2 ) 
			nombre2, nbNombre2 = nombre2:gsub( '%-?%f[%d.,][%d., ]+%f[%D]', p.formatNombre )
			if intervalle == '–' and nombre:sub( 1, 2 ) == '−' then
				intervalle = ' – '
			end
		end
	end
	
	-- ±
	local approximation
	if trim( args['±'] ) then
		approximation = '±\194\160' .. p.formatNombre( args['±'] )
	end
	
	-- puissance de 10
	local exposant = trim( args.e )
	if exposant then
		if nombre then
			exposant = '×\194\16010<sup>' .. exposant .. '</sup>'
		else
			exposant = '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 = tonumber( p.parseNombre( args[ 2 * i + 1 ] ) )
		local sep = ''
		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 and not par and exp < 0 then
					par = true
					table.insert( nomUnits, 'par' )
				end
			end
		end
		local expUnit = exp and '<sup>' .. exp .. '</sup>' or ''
		units = units .. sep .. unit .. expUnit
		table.insert( nomUnits, p.nomUnit( unit, exp ) )
		i = i + 1
		unit = trim( args[ 2 * i ] )
	end
	
	if units == '°' then
		nombre = nombre and nombre .. '°'
		nombre2 = nombre2 and nombre2 .. '°'
		approximation = approximation and approximation .. '°'
		units = nil
	end 
	if intervalle then
		nombre = nombre .. intervalle .. nombre2
	end
	
	local wiki = { nombre }
	table.insert( wiki, approximation ) 
	table.insert( wiki, exposant )
	if nomUnits[1] then
		units = string.format( '<abbr class=abbr title="%s">%s</abbr>', table.concat( nomUnits, ' ' ), 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' and type( frame.getParent ) == 'function' then
			args = frame:getParent().args;
	end
	if args then
		if #args == 1 
			and not ( args.e or args.et or args['à'] or args['±'] )
			and trim( args[1] ) 
			and args[1]:match('[^%d,. -]') 
		then
			args = p.parseUnit( trim( args[1] ) )
		end
		return p._unite( args )
	end
end

return p