Module:Chem2: Difference between revisions
Appearance
Content deleted Content added
Per multiple discussions on the talk page, increase the superscript/subscript font size to 80% (from 70%) and implement it without a <br>. Tag: Reverted |
Copy from sandbox Tag: Reverted |
||
Line 143: | Line 143: | ||
function su(up, down) |
function su(up, down) |
||
if up == "" then |
|||
⚫ | |||
return ('<sub class="template-chem2-sub">%s</sub>'):format(down) |
|||
end |
|||
if down == "" then |
|||
return ('<sup class="template-chem2-sup">%s</sup>'):format(up) |
|||
end |
|||
⚫ | |||
end |
end |
||
Revision as of 12:56, 28 November 2021
![]() | This module is rated as ready for general use. It has reached a mature form and is thought to be relatively bug-free and ready for use wherever appropriate. It is ready to mention on help pages and other Wikipedia resources as an option for new users to learn. To reduce server load and bad output, it should be improved by sandbox testing rather than repeated trial-and-error editing. |
![]() | This module is subject to page protection. It is a highly visible module in use by a very large number of pages, or is substituted very frequently. Because vandalism or mistakes would affect many pages, and even trivial editing might cause substantial load on the servers, it is protected from editing. |
![]() | This Lua module is used on approximately 8,100 pages and changes may be widely noticed. Test changes in the module's /sandbox or /testcases subpages, or in your own module sandbox. Consider discussing changes on the talk page before implementing them. |
![]() | This module depends on the following other modules: |
![]() | This module uses TemplateStyles: |
This module implements {{chem2}}. Please see its documentation for details.
local getArgs = require('Module:Arguments').getArgs
local p = {} -- module's table
-- Elements with wiki links
local am = {
H = "[[Hydrogen|H]]",
He = "[[Helium|He]]",
Li = "[[Lithium|Li]]",
Be = "[[Beryllium|Be]]",
B = "[[Boron|B]]",
C = "[[Carbon|C]]",
N = "[[Nitrogen|N]]",
O = "[[Oxygen|O]]",
F = "[[Fluorine|F]]",
Ne = "[[Neon|Ne]]",
Na = "[[Sodium|Na]]",
Mg = "[[Magnesium|Mg]]",
Al = "[[Aluminium |Al]]",
Si = "[[Silicon|Si]]",
P = "[[Phosphorus|P]]",
S = "[[Sulfur|S]]",
Cl = "[[Chlorine|Cl]]",
Ar = "[[Argon|Ar]]",
K = "[[Potassium|K]]",
Ca = "[[Calcium|Ca]]",
Sc = "[[Scandium|Sc]]",
Ti = "[[Titanium|Ti]]",
V = "[[Vanadium|V]]",
Cr = "[[Chromium|Cr]]",
Mn = "[[Manganese|Mn]]",
Fe = "[[Iron|Fe]]",
Co = "[[Cobalt|Co]]",
Ni = "[[Nickel|Ni]]",
Cu = "[[Copper|Cu]]",
Zn = "[[Zinc|Zn]]",
Ga = "[[Gallium|Ga]]",
Ge = "[[Germanium|Ge]]",
As = "[[Arsenic|As]]",
Se = "[[Selenium|Se]]",
Br = "[[Bromine|Br]]",
Kr = "[[Krypton|Kr]]",
Rb = "[[Rubidium|Rb]]",
Sr = "[[Strontium|Sr]]",
Y = "[[Yttrium|Y]]",
Zr = "[[Zirconium|Zr]]",
Nb = "[[Niobium|Nb]]",
Mo = "[[Molybdenum|Mo]]",
Tc = "[[Technetium|Tc]]",
Ru = "[[Ruthenium|Ru]]",
Rh = "[[Rhodium|Rh]]",
Pd = "[[Palladium|Pd]]",
Ag = "[[Silver|Ag]]",
Cd = "[[Cadmium|Cd]]",
In = "[[Indium|In]]",
Sn = "[[Tin|Sn]]",
Sb = "[[Antimony|Sb]]",
Te = "[[Tellurium|Te]]",
I = "[[Iodine|I]]",
Xe = "[[Xenon|Xe]]",
Cs = "[[Caesium|Cs]]",
Ba = "[[Barium|Ba]]",
La = "[[Lanthanum|La]]",
Ce = "[[Cerium|Ce]]",
Pr = "[[Praseodymium|Pr]]",
Nd = "[[Neodymium|Nd]]",
Pm = "[[Promethium|Pm]]",
Sm = "[[Samarium|Sm]]",
Eu = "[[Europium|Eu]]",
Gd = "[[Gadolinium|Gd]]",
Tb = "[[Terbium|Tb]]",
Dy = "[[Dysprosium|Dy]]",
Ho = "[[Holmium|Ho]]",
Er = "[[Erbium|Er]]",
Tm = "[[Thulium|Tm]]",
Yb = "[[Ytterbium|Yb]]",
Lu = "[[Lutetium|Lu]]",
Hf = "[[Hafnium|Hf]]",
Ta = "[[Tantalum|Ta]]",
W = "[[Tungsten|W]]",
Re = "[[Rhenium|Re]]",
Os = "[[Osmium|Os]]",
Ir = "[[Iridium|Ir]]",
Pt = "[[Platinum|Pt]]",
Au = "[[Gold|Au]]",
Hg = "[[Mercury (element)|Hg]]",
Tl = "[[Thallium|Tl]]",
Pb = "[[Lead|Pb]]",
Bi = "[[Bismuth|Bi]]",
Po = "[[Polonium|Po]]",
At = "[[Astatine|At]]",
Rn = "[[Radon|Rn]]",
Fr = "[[Francium|Fr]]",
Ra = "[[Radium|Ra]]",
Ac = "[[Actinium|Ac]]",
Th = "[[Thorium|Th]]",
Pa = "[[Protactinium|Pa]]",
U = "[[Uranium|U]]",
Np = "[[Neptunium|Np]]",
Pu = "[[Plutonium|Pu]]",
Am = "[[Americium|Am]]",
Cm = "[[Curium|Cm]]",
Bk = "[[Berkelium|Bk]]",
Cf = "[[Californium|Cf]]",
Es = "[[Einsteinium|Es]]",
Fm = "[[Fermium|Fm]]",
Md = "[[Mendelevium|Md]]",
No = "[[Nobelium|No]]",
Lr = "[[Lawrencium|Lr]]",
Rf = "[[Rutherfordium|Rf]]",
Db = "[[Dubnium|Db]]",
Sg = "[[Seaborgium|Sg]]",
Bh = "[[Bohrium|Bh]]",
Hs = "[[Hassium|Hs]]",
Mt = "[[Meitnerium|Mt]]",
Ds = "[[Darmstadtium|Ds]]",
Rg = "[[Roentgenium|Rg]]",
Cp = "[[Copernicium|Cp]]",
Nh = "[[Nihonium|Nh]]",
Fl = "[[Flerovium|Fl]]",
Mc = "[[Moscovium|Mc]]",
Lv = "[[Livermorium|Lv]]",
Ts = "[[Tennessine|Ts]]",
Og = "[[Oganesson|Og]]",
}
local T_ELEM = 0 -- token types
local T_NUM = 1 -- number
local T_OPEN = 2 -- open '('
local T_CLOSE = 3 -- close ')'
local T_PM_CHARGE = 4 -- + or −
local T_WATER = 6 -- .xH2O x number
local T_CRYSTAL = 9 -- .x
local T_CHARGE = 8 -- charge (x+), (x-)
local T_SUF_CHARGE = 10 -- suffix and charge e.g. 2+ from H2+
local T_SUF_CHARGE2 = 12 -- suffix and (charge) e.g. 2(2+) from He2(2+)
local T_SPECIAL = 14 -- starting with \ e.g. \d for double bond (=)
local T_SPECIAL2 = 16 -- starting with \y{x} e.g. \i{12} for isotope with mass number 12
local T_ARROW_R = 17 -- match: ->
local T_ARROW_EQ = 18 -- match: <->
local T_UNDERSCORE = 19 -- _{ ... }
local T_CARET = 20 -- ^{ ... }
local T_NOCHANGE = 30 -- Anything else like ☃
function su(up, down)
if up == "" then
return ('<sub class="template-chem2-sub">%s</sub>'):format(down)
end
if down == "" then
return ('<sup class="template-chem2-sup">%s</sup>'):format(up)
end
return ('<span class="template-chem2-su"><span>%s</span><span>%s</span></span>'):format(up, down)
end
function DotIt()
return '·'
end
function item(f) -- (iterator) returns one token (type, value) at a time from the formula 'f'
local i = 1
local first = true
return function ()
local t, x = nil, nil
if (first and f:match('^[0-9]', i)) then
x = f:match('^[%d.]+', i); t = T_NOCHANGE; i = i + x:len(); -- matching coefficient (need a space first)
elseif i <= f:len() then
x = f:match('^%s+[%d.]+', i); t = T_NOCHANGE; -- matching coefficient (need a space first)
if not x then x = f:match('^%s[+]', i); t = T_NOCHANGE; end -- matching + (H2O + H2O)
if not x then x = f:match('^%&%#[%w%d]+%;', i); t = T_NOCHANGE; end -- &#...;
if not x then x = f:match('^%<%-%>', i); t = T_ARROW_EQ; end -- matching <->
if not x then x = f:match('^%-%>', i); t = T_ARROW_R; end -- matching ->
if not x then x = f:match('^%u%l*', i); t = T_ELEM; end -- matching symbols like Aaaaa
if not x then x = f:match('^%d+[+-]', i); t = T_SUF_CHARGE; end -- matching x+, x-
if not x then x = f:match('^%d+%(%d*[+-]%)', i); t = T_SUF_CHARGE2; end -- matching x(y+/-), x(+/-)
if not x then x = f:match('^%(%d*[+-]%)', i); t = T_CHARGE; end -- matching (x+) (xx+), (x-) (xx-)
if not x then x = f:match('^[%d.]+', i); t = T_NUM; end -- matching number
if not x then x = f:match('^[(|{|%[]', i); t = T_OPEN; end -- matching ({[
if not x then x = f:match('^[)|}|%]]', i); t = T_CLOSE; end -- matching )}]
if not x then x = f:match('^[+-]', i); t = T_PM_CHARGE; end -- matching + or -
if not x then x = f:match('^%*[%d.]*H2O', i); t = T_WATER; end -- Crystal water
if not x then x = f:match('^%*[%d.]*', i); t = T_CRYSTAL; end -- Crystal
if not x then x = f:match('^[\\].{%d+}', i); t = T_SPECIAL2; end -- \y{x}
if not x then x = f:match('^[\\].', i); t = T_SPECIAL; end -- \x
if not x then x = f:match('^_{[^}]*}', i); t = T_UNDERSCORE; end -- _{...}
if not x then x = f:match('^\^{[^}]*}', i); t = T_CARET; end -- ^{...}
if not x then x = f:match('^.', i); t = T_NOCHANGE; end --the rest - one by one
if x then i = i + x:len(); else i = i + 999; error("Invalid character in formula! : "..f) end
end
first = false
return t, x
end
end
function p._chem(args)
local f = args[1] or ''
f = string.gsub(f, "–", "-") -- replace – with - (hyphen not ndash)
f = string.gsub(f, "−", "-") -- replace – with - (hyphen not minus sign)
local sumO = 0
local formula = ''
local t, x
local link = args['link'] or ""
local auto = args['auto'] or ""
if not (link == '') then formula = formula .. "[[" .. link .. "|"; end -- wikilink start [[link|
for t, x in item(f) do
if t == T_ELEM then
if (auto == '') then formula = formula .. x
elseif am[x] then formula = formula .. am[x]; am[x] = x
else formula = formula .. x
end
elseif t == T_COEFFICIENT then formula = formula .. x
elseif t == T_NUM then formula = formula .. su("", x);
elseif t == T_OPEN then formula = formula .. x; sumO = sumO + 1; -- ( {
elseif t == T_CLOSE then formula = formula .. x; sumO = sumO -1; -- ) }
elseif t == T_PM_CHARGE then formula = formula .. su(string.gsub(x, "-", "−"), "");
elseif t == T_SUF_CHARGE then
formula = formula .. su(string.gsub(string.match(x, "[+-]"), "-", "−"), string.match(x, "%d+"), "");
elseif t == T_SUF_CHARGE2 then
formula = formula .. su(string.sub(string.gsub(string.match(x, "%(%d*[+-]"), "-", "−"), 2, -1), string.match(x, "%d+"))
elseif t == T_CHARGE then formula = formula .. "<sup>"; if string.match(x, "%d+") then formula = formula .. string.match(x, "%d+"); end formula = formula .. string.gsub(string.match(x, "[%+-]"), "-", "−") .. "</sup>"; -- can not concatenat a nil value from string.match(x, "%d+");
elseif t == T_CRYSTAL then formula = formula .. DotIt() .. string.gsub( x, "*", '', 1 );
elseif t == T_SPECIAL then
parameter = string.sub(x, 2, 2) -- x fra \x
if parameter == "s" then formula = formula .. "−" -- single bond
elseif parameter == "d" then formula = formula .. "=" -- double bond
elseif parameter == "t" then formula = formula .. "≡" -- tripple bond
elseif parameter == "q" then formula = formula .. "≣" -- Quadruple bond
elseif parameter == "h" then formula = formula .. "η" -- η, hapticity
elseif parameter == "*" then formula = formula .. "*" -- *, normal *
elseif parameter == "-" then formula = formula .. "-" -- -
elseif parameter == "\\" then formula = formula .. "\\" -- \
elseif parameter == "\'" then formula = formula .. "'" -- html-code for '
end
elseif t == T_SPECIAL2 then -- \y{x}
parameter = string.sub(x, 2, 2) -- y fra \y{x}
if parameter == "h" then --[[Hapticity]]
if (auto == '') then formula = formula .. "η<sup>" .. string.match(x, '%d+') .. "</sup>-"
else
formula = formula .. "[[Hapticity|η<sup>" .. string.match(x, '%d+') .. "</sup>]]-"
end
elseif parameter == "m" then formula = formula .. "μ<sub>" .. string.match(x, '%d+') .. "</sub>-" -- mu ([[bridging ligand]])
end
elseif t == T_WATER then
if string.match(x, "^%*[%d.]") then
formula = formula .. DotIt() .. string.match(x, "%f[%.%d]%d*%.?%d*%f[^%.%d%]]") .. "H<sub>2</sub>O";
else
formula = formula .. DotIt() .. "H<sub>2</sub>O";
end
elseif t == T_UNDERSCORE then formula = formula .. su("", string.sub(x,3,-2)) -- x contains _{string}
elseif t == T_CARET then formula = formula .. su(string.sub(x,3,-2), "") -- x contains ^{string}
elseif t == T_ARROW_R then formula = formula .. " → "
elseif t == T_ARROW_EQ then formula = formula .. " ⇌ "
elseif t == T_NOCHANGE then formula = formula .. x; -- The rest - everything which isn't captured by the regular expresions. E.g. wikilinks and pipes
else error('unreachable - ???') end -- in fact, unreachable
end
if not (link == nil or link == '') then formula = formula .. "]]"; end -- wikilink closing ]]
formula = mw.getCurrentFrame():preprocess('<templatestyles src="Module:Chem2/styles.css"/>') ..
'<span class="chemf nowrap">' .. formula .. '</span>'
if args[2] or args[3] or args[4] then
formula = formula .. require('Module:If preview')._warning{
'{{chem2}} was called with multiple positional arguments. It should have just one, e.g. {{chem2|H2O}}.'
}
end
return formula
end
function p.chem(frame)
local args = getArgs(frame)
return p._chem(args)
end
return p