Module:Unité
From CryptoWiki
Revision as of 06:06, 2 January 2022 by wiki_crypto>Od1n (la méthode d'escaping précédente était erronée car elle mettait encore des chiffres, qui étaient ensuite détectés à tort, mais comme il y avait moins de 4 chiffres il n'y avait pas de formattage effectué dessus en pratique ; de plus, je suppose que cet escaping est peu rencontré en pratique, car il faut qu'il y ait une <ref> dans la partie "nombre" de l'input ; donc voilà, nouvelle méthode et factorisée de sorte à pouvoir la réutiliser ailleurs)
Documentation for this module may be created at 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 -- 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 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', ' ' ) :gsub( ' ', ' ' ) :gsub( '\226\128[\128-\138\175]', ' ' ) -- U+2002 à U+200A et U+202F -- 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 '' 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 -- 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 exponent = ' ×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, 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 > 3 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 = 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 nombres = nombres :gsub( '%-?%f[%d.,][%d., ]*%de[+-]?%d+', formatN ) :gsub( '%-?%f[%d.,][%d., ]*%d', formatN ) -- 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 et tiret ['±'] = '±', ['+-'] = '±', ['+/-'] = '±', ['+'] = '+', ['−'] = '−', -- signe moins ['×'] = '×', x = '×', ['*'] = '×', ['××'] = '××', xx = '××', ['**'] = '××', } -- valeur numérique local match, capture = toParse:match( '^(([%d., ]+%f[^d%(])%s*)' ) local prefix if not match then -- cas ou le nombre est remplcé par un ou plusieurs points d'interrogation match, prefix = toParse:match( '^((%?+)%s*)' ) end if not match 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) match, prefix, capture = toParse:match( '^(([%a]+[.,]?[: ]* )([+-]?%f[%d.,][%d., ]*%d%f[%D])%s*)' ) end if not match then -- cas ou le nombre est précédé par un signe, un symbole ASCII, ou suivit d'une incerititude entre parenthèse match, prefix, capture = toParse:match( '^(([(<>=~ ]*)([+-]?%f[%d.,][%d., ]*%d%(?%d*%)?)%s*)' ) end if not match then -- cas ou le nombre est précédé par un symbole ≤, ≥ ou ≈ match, prefix, capture = toParse:match( '^((\226\137[\164\165\136] ?)([+-]?%f[%d.,][%d., ]*%d%f[%D])%s*)' ) end result = { capture or false, prefix = prefix } if match then toParse = toParse:sub( match:len() + 1 ) -- point de suspensions (ex π = 3.14159...) match = toParse:match( '^…%s*' ) if not match then match, capture = toParse:match( '^%.%.%.%s*' ) end if match then result[1] = result[1] .. '…' toParse = toParse:sub( match:len() + 1 ) end -- fraction match, capture = toParse:match( '^((%d*/%d+)%s*)' ) if not match then match, capture = toParse:match( '^((\194[\188-\190])%s*)' ) -- ¼ à ¾ end if not match then match, capture = toParse:match( '^((\226\133[\144-\158])%s*)' ) -- ⅐ à ⅞ end if match then if 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( 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<>' ) or toParse:match( 'UNIQ%-%-%a+%-%x%x%x%x%x%x%x%x%-QINU' ) then result[ #result + 1] = 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 not match then -- l/100 km match, unit, exp = mw.ustring.match( toParse, '^((/100 ?[^%s%d/]+) ?(%-?%d*)%s*)' ) end if match 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 = match exp = '' end if Data.unit[ unit ] or mw.ustring.match( unit, '[%a€£$«»]' ) then result[ #result + 1] = unit result[ #result + 1] = exp toParse = toParse:sub( match:len() + 1 ) else break end end until toParse == '' or not match end if toParse == '' then 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 ) 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 -- 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 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 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 if nombre then wiki[ #wiki + 1 ] = '\194\160' end wiki[ #wiki + 1 ] = args.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 == '–' 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 == '/' then -- espace demi-cadratin (U+2002 ou  ) avec / wiki[ #wiki + 1 ] = ' / ' elseif name == '××' then wiki[ #wiki + 1 ] = '\194\160×\194\160' elseif name == '×' or name == '±' then wiki[ #wiki + 1 ] = '\194\160' .. name .. '\194\160' else wiki[ #wiki + 1 ] = ' ' .. 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 units ~= '' then if unit:sub( 1, 1 ) == '/' then sep = '/' unit = unit:sub( 2 ) if not par then par = true nomUnits[ #nomUnits + 1 ] = 'par' end else sep = '\194\160' end 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 ] = '\194\160× 10<sup>' .. exposant .. '</sup>' else wiki[ #wiki + 1 ] = '10<sup>' .. exposant .. '</sup>' end end if units ~= '' then local sep = '\194\160' 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( '\194\160', ' ' ) 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 args[1] = trim( args[1] ) or false if args[1] 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] and 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 -- 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 then cat = errorCat end return ( p._unite( args ) or '' ) .. cat end end return p