Module:Chem2: Difference between revisions
Appearance
Content deleted Content added
Add preview warning if this is called like {{chem}}, with multiple numbered arguments, as mentioned on talk page. Make indentation consistent. Tag: Reverted |
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 |
||
Line 142: | Line 142: | ||
local T_NOCHANGE = 30 -- Anything else like ☃ |
local T_NOCHANGE = 30 -- Anything else like ☃ |
||
function su(up, down) |
function su(up, down) |
||
return ('<span class=\"template-chem2-su\"><span>%s</span><span>%s</span></span>'):format(up, down) |
|||
if (down == "") then |
|||
return "<span style=\"display:inline-block; margin-bottom:-0.3em; vertical-align:0.8em; line-height:1.2em; font-size:70%; text-align:left;\">" .. up .. "<br /></span>"; |
|||
else |
|||
return "<span style=\"display:inline-block; margin-bottom:-0.3em; vertical-align:-0.4em; line-height:1.2em; font-size:70%; text-align:left;\">" .. up .. "<br />" .. down .. "</span>"; |
|||
end |
|||
end |
end |
||
Line 261: | Line 257: | ||
if not (link == nil or link == '') then formula = formula .. "]]"; end -- wikilink closing ]] |
if not (link == nil or link == '') then formula = formula .. "]]"; end -- wikilink closing ]] |
||
formula = '< |
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 |
if args[2] or args[3] or args[4] then |
||
formula = formula .. require('Module:If preview')._warning{ |
formula = formula .. require('Module:If preview')._warning{ |
Revision as of 22:02, 24 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)
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