Chemical calculator: Difference between revisions

m
m (→‎{{header|Wren}}: Minor tidy)
 
(46 intermediate revisions by 18 users not shown)
Line 3:
Given a molecule's chemical formula, calculate the &nbsp; [https://en.wikipedia.org/wiki/Molar_mass <u>molar mass</u>].
 
 
;Introduction
* A molecule consists of atoms. &nbsp; E.g. water, H2O, has two hydrogen atoms and one oxygen atom
* The mass of &nbsp; H2O &nbsp; is &nbsp; 1.008 * 2 + 15.999 = 18.015
* An atom name consists of one upper-case letter followed by zero, one or two lower-case letters.
** H &nbsp; &nbsp; &nbsp; (Hydrogenhydrogen)
** He &nbsp; &nbsp; (Heliumhelium)
** Uue &nbsp; (Ununenniumununennium)
* The number of atoms is stated behind the atom or atom group
* An atom group is specified using parenthesis. &nbsp; E.g. Butyricbutyric acid, (CH3)2CHCOOH, has two CH3 groups
* A group may contain other groups, e.g. &nbsp; COOH(C(CH3)2)3CH3
 
 
Line 31:
 
;Atom masses
A mapping between mostsome recognized element names and atomic mass follows in comma separated value formatis:
<pre style="overflow:scroll; height:345px82ex;">
H, 1.008
He, 4.002602
Li, 6.94
Be, 9.0121831
B, 10.81
C, 12.011
N, 14.007
O, 15.999
F, 18.998403163
Ne, 20.1797
Na, 22.98976928
Mg, 24.305
Al, 26.9815385
Si, 28.085
P, 30.973761998
S, 32.06
Cl, 35.45
K, 39.0983
Ar, 39.948
Ca, 40.078
Sc, 44.955908
Ti, 47.867
V, 50.9415
Cr, 51.9961
Mn, 54.938044
Fe, 55.845
Ni, 58.6934
Co, 58.933194
Cu, 63.546
Zn, 65.38
Ga, 69.723
Ge, 72.63
As, 74.921595
Se, 78.971
Br, 79.904
Kr, 83.798
Rb, 85.4678
Sr, 87.62
Y, 88.90584
Zr, 91.224
Nb, 92.90637
Mo, 95.95
Ru, 101.07
Rh, 102.9055
Pd, 106.42
Ag, 107.8682
Cd, 112.414
In, 114.818
Sn, 118.71
Sb, 121.76
I, 126.90447
Te, 127.6
Xe, 131.293
Cs, 132.90545196
Ba, 137.327
La, 138.90547
Ce, 140.116
Pr, 140.90766
Nd, 144.242
Pm, 145
Sm, 150.36
Eu, 151.964
Gd, 157.25
Tb, 158.92535
Dy, 162.5
Ho, 164.93033
Er, 167.259
Tm, 168.93422
Yb, 173.054
Lu, 174.9668
Hf, 178.49
Ta, 180.94788
W, 183.84
Re, 186.207
Os, 190.23
Ir, 192.217
Pt, 195.084
Au, 196.966569
Hg, 200.592
Tl, 204.38
Pb, 207.2
Bi, 208.9804
Po, 209
At, 210
Rn, 222
Fr, 223
Ra, 226
Ac, 227
Pa, 231.03588
Th, 232.0377
Np, 237
U, 238.02891
Am, 243
Pu, 244
Cm, 247
Bk, 247
Cf, 251
Es, 252
Fm, 257
Ubn, 299
Uue, 315</pre>
 
 
;Examples:
<langsyntaxhighlight lang="python">assert 1.008 == molar_mass('H') # hydrogen
assert 2.016 == molar_mass('H2') # hydrogen gas
assert 18.015 == molar_mass('H2O') # water
Line 147 ⟶ 146:
assert 176.124 == molar_mass('C6H4O2(OH)4') # vitamin C
assert 386.664 == molar_mass('C27H46O') # cholesterol
assert 315 == molar_mass('Uue') # ununennium</langsyntaxhighlight>
 
 
Line 153 ⟶ 152:
:* &nbsp; Wikipedia article: &nbsp; [https://en.wikipedia.org/wiki/Molecular_mass Molecular mass]
<br><br>
=={{header|ALGOL 68}}==
{{Trans|ALGOL W}}
<syntaxhighlight lang="algol68">
BEGIN # chemical calculator - calculate the molar mass of compounds #
# MODE to hold element symbols and masses #
MODE ATOM = STRUCT( STRING symbol, REAL mass, REF ATOM next );
 
# returns the molar mass of the specified molecule #
PROC molarmass = ( STRING molecule )REAL:
BEGIN
CHAR c;
BOOL had error := FALSE;
INT ch max = UPB molecule;
INT ch pos := LWB molecule - 1;
 
# reports a syntax error in the molecule starting at position ch pos #
PROC error = ( STRING message )VOID:
BEGIN
print( ( "Syntax error in molecule: ", molecule, message, newline ) );
print( ( " " ) );
FOR i TO ch pos - 1 DO print( ( " " ) ) OD;
print( ( "^", newline ) );
# ensure parsing stops #
had error := TRUE;
ch pos := ch max * 2
END # error # ;
# gets the next character from the molecule #
PROC next char = VOID:
c := IF ch pos +:= 1; ch pos > ch max THEN " " ELSE molecule[ ch pos ] FI;
# parses a compound: a sequence of element names and bracketed compounds, each with #
# an optional trailing repeat count #
PROC parse compound = REAL:
BEGIN
# parses an element symbol feom the molecule and returns its mass #
PROC parse atom = REAL:
BEGIN
STRING symbol := c;
next char;
FOR i TO 2 WHILE c >= "a" AND c <= "z" DO
symbol +:= c;
next char
OD;
# find the element in the table #
ATOM element := atoms[ ABS symbol[ LWB symbol ] - ABS "A" ];
WHILE IF element IS REF ATOM(NIL) THEN FALSE ELSE symbol OF element /= symbol FI DO
element := next OF element
OD;
IF element ISNT REF ATOM(NIL)
THEN # found the element # mass OF element
ELSE # unknown element #
ch pos -:= 1;
error( "Unrecognised element." );
0
FI
END # parse atom # ;
REAL mass := 0;
WHILE NOT had error AND ( ( c >= "A" AND c <= "Z" ) OR c = "(" ) DO
REAL item mass := 0;
IF c >= "A" AND c <= "Z" THEN item mass := parse atom
ELIF c = "(" THEN
# bracketed group #
next char;
item mass := parse compound;
IF IF ch pos > ch max THEN " " ELSE molecule[ ch pos ] FI /= ")" THEN
error( "Expected "")""." )
FI;
next char
FI;
IF c >= "0" AND c <= "9" THEN
# have a repeat count #
INT count := 0;
WHILE NOT had error AND c >= "0" AND c <= "9" DO
count *:= 10 +:= ABS c - ABS "0";
next char
OD;
item mass *:= count
FI;
mass +:= item mass
OD;
mass
END # parse compound # ;
next char;
REAL mass = parse compound;
IF ch pos <= ch max THEN error( "Unexpected text after the molecule." ) FI;
mass
END # molar mass # ;
# hash table of atome, hash is the first character of the symbol - "A" #
[ 0 : 25 ]REF ATOM atoms; FOR i FROM LWB atoms TO UPB atoms DO atoms( i ) := NIL OD;
BEGIN # setup element symbols and masses as specified in the task #
# adds an element and its mass to the atoms table #
OP / = ( STRING symbol, REAL mass )VOID:
BEGIN
INT index = ABS symbol[ LWB symbol ] - ABS "A";
atoms[ index ] := HEAP ATOM := ATOM( symbol, mass, atoms[ index ] )
END # / # ;
OP / = ( STRING symbol, INT mass )VOID: symbol / REAL(mass);
OP / = ( CHAR symbol, REAL mass )VOID: STRING(symbol) / mass;
PROC lanthanides = VOID:
BEGIN
"La"/138.90547;"Ce"/140.116 ;"Pr"/140.90766;"Nd"/144.242 ;"Pm"/145 ;
"Sm"/150.36 ;"Eu"/151.964 ;"Gd"/157.25 ;"Tb"/158.92535;"Dy"/162.5 ;
"Ho"/164.93033;"Er"/167.259 ;"Tm"/168.93422;"Yb"/173.054 ;"Lu"/174.9668;
SKIP
END # lanthanides # ;
PROC actinides = VOID:
BEGIN
"Ac"/227 ;"Th"/232.0377;"Pa"/231.03588;"U" /238.02891;"Np"/237 ;
"Pu"/244 ;"Am"/243 ;"Cm"/247; "Bk"/247; "Cf"/251 ;
"Es"/252 ;"Fm"/257 ;#Md ; No ; Lr ;#
SKIP
END # actinides # ;
"H" /1.008 ;"Li"/ 6.94 ;"Na"/22.98976928 ;"K" /39.0983 ;"Rb"/85.4678 ;"Cs"/132.90545196;"Fr"/223 ;
"Be"/ 9.0121831 ;"Mg"/24.305 ;"Ca"/40.078 ;"Sr"/87.62 ;"Ba"/137.327 ;"Ra"/226 ;
"Sc"/44.955908;"Y" /88.90584 ;lanthanides ;actinides;
"Ti"/47.867 ;"Zr"/91.224 ;"Hf"/178.49 ;# Rf #
"V" /50.9415 ;"Nb"/92.90637 ;"Ta"/180.94788 ;# Db #
"Cr"/51.9961 ;"Mo"/95.95 ;"W" /183.84 ;# Sg #
"Mn"/54.938044;#Tc #"Re"/186.207 ;# Bh #
"Fe"/55.845 ;"Ru"/101.07 ;"Os"/190.23 ;# Hs #
"Co"/58.933194;"Rh"/102.9055 ;"Ir"/192.217 ;# Mt #
"Ni"/58.6934 ;"Pd"/106.42 ;"Pt"/195.084 ;# Ds #
"Cu"/63.546 ;"Ag"/107.8682 ;"Au"/196.966569 ;# Rg #
"Zn"/65.38 ;"Cd"/112.414 ;"Hg"/200.592 ;# Cn #
"B" /10.81 ;"Al"/26.9815385 ;"Ga"/69.723 ;"In"/114.818 ;"Tl"/204.38 ;# Nh #
"C" /12.011 ;"Si"/28.085 ;"Ge"/72.63 ;"Sn"/118.71 ;"Pb"/207.2 ;# Fl #
"N" /14.007 ;"P" /30.973761998;"As"/74.921595;"Sb"/121.76 ;"Bi"/208.9804 ;# Ms #
"O" /15.999 ;"S" / 32.06 ;"Se"/78.971 ;"Te"/127.6 ;"Po"/209 ;# Lv #
"F" /18.998403163;"Cl"/35.45 ;"Br"/79.904 ;"I" /126.90447;"At"/210 ;# Ts #
"He"/4.002602;"Ne"/20.1797 ;"Ar"/39.948 ;"Kr"/83.798 ;"Xe"/131.293 ;"Rn"/222 ;# Og #
# --- hypothetical eigth period elements --/ # "Uue"/315;"Ubn"/299;
SKIP
END;
BEGIN # test cases #
PROC test = ( REAL expected mass, STRING molecule )VOID:
BEGIN
REAL mass = molar mass( molecule );
STRING pad = IF INT length = ( UPB molecule - LWB molecule ) + 1;
length > 20
THEN ""
ELSE ( 20 - length ) * " "
FI;
print( ( newline, pad, molecule, ":", fixed( mass, -9, 3 ) ) );
REAL diff = expected mass - mass;
IF diff > 1e-12 OR diff < -1e-12 THEN
print( ( " expected:", fixed( expected mass, -9, 3 ) ) )
FI
END # test # ;
test( 1.008, "H" ); test( 2.016, "H2" ); test( 18.015, "H2O" );
test( 142.03553856000002, "Na2SO4" ); test( 84.162, "C6H12" );
test( 186.29499999999996, "COOH(C(CH3)2)3CH3" ); test( 350.45, "UueCl" )
END
END
</syntaxhighlight>
{{out}}
<pre>
H: 1.008
H2: 2.016
H2O: 18.015
Na2SO4: 142.036
C6H12: 84.162
COOH(C(CH3)2)3CH3: 186.295
UueCl: 350.450
</pre>
 
=={{header|ALGOL W}}==
Algol W has fixed length strings and no regular expressions, this parses the molecule with a simple recursive descent parser.<br>
Some error checking is included.
<langsyntaxhighlight lang="algolw">begin
% calculates the molar mass of the specified molecule %
real procedure molar_mass ( string(256) value molecule ) ; begin
Line 189 ⟶ 351:
real procedure parseCompound ; begin
real mass, itemMass;
% parses an element symbol fromfeom the molecule and returnsretutns its mass %
real procedure parseAtom ; begin
string(3) symbol;
Line 267 ⟶ 429:
A("Es",252 );A("Fm",257 ); % Md % %, No % % Lr %
end Actinides ;
A("Li",real 6.94 )CsMass;A("Na",22.98976928 );A("K",CsMass 39.0983:= );A("Rb", 85.4678 );A("Cs",132.90545196);A("Fr", 223 );
A("BeLi", 96.012183194 );A("MgNa",2422.305 98976928 );A("CaK",40.078 39.0983 );A("SrRb", 8785.62 4678 );A("BaCs",137.327 CsMass );A("RaFr", 226 223);
A("Be", 9.0121831 );A("Mg",24.305 );A("ScCa",4440.955908078 );A("YSr", 8887.90584);62 Lanthanides);A("Ba",137.327 Actinides);A("Ra",226);
A("TiSc",4744.867 955908);A("ZrY", 91.224 );A("Hf",17888.49 90584);Lanthanides; % Rf %Actinides;
A("VTi", 5047.9415867 );A("NbZr", 9291.90637224 );A("TaHf",180178.9478849 ); % Db Rf %
A("CrV",51 50.99619415 );A("MoNb", 9592.95 90637);A("WTa", 183180.84 94788 ); % Sg Db %
A("MnCr",5451.9380449961 );A("Mo", %95.95 Tc % );A("ReW",186 183.207 84 ); % Bh Sg %
A("FeMn",5554.845938044); % Tc );A("Ru",101.07 ); % A("OsRe",190186.23 207 ); % Hs Bh %
A("CoFe",5855.933194845 );A("RhRu",102101.905507 );A("IrOs",192190.217 23 ); % Mt Hs %
A("NiCo",58.6934 933194);A("PdRh",106102.42 9055 );A("PtIr",195192.084 217 ); % Ds Mt %
A("CuNi",6358.546 6934 );A("AgPd",107106.868242 );A("AuPt",196195.966569084 ); % Rg Ds %
A("ZnCu",6563.38 546 );A("CdAg",112107.414 8682 );A("HgAu",200196.592 966569); % Cn Rg %
A("B", 10.81 );A("Al",26.9815385 ); A("GaZn",6965.72338 );A("InCd",114112.818414 );A("TlHg",204200.38 592 ); % Nh Cn %
A("CB", 1210.01181 );A("SiAl",2826.085 9815385 );A("GeGa",7269.63 723 );A("SnIn",118114.71 818 );A("PbTl",207204.2 38 ); % Fl Nh %
A("NC", 1412.007011 );A("PSi", 3028.973761998085 );A("AsGe",7472.92159563 );A("SbSn",121118.7671 );A("BiPb",208207.98042 ); % Ms Fl %
A("ON", 1514.999007 );A("SP", 3230.06 973761998);A("SeAs",7874.971 921595);A("TeSb",127121.6 76 );A("PoBi",209 208.9804 ); % Lv Ms %
A("FO", 1815.998403163999 );A("ClS",35 32.4506 );A("BrSe",7978.904971 );A("ITe", 126127.904476 );A("AtPo",210 209 ); % Ts Lv %
A("NeF",20 18.1797 998403163);A("ArCl",3935.94845 );A("KrBr",8379.798904 );A("XeI",131 126.293 90447);A("RnAt",222 210 ); % Og Ts %
A("Ne",20.1797 );A("Ar",39.948 );A("Kr",83.798 );A("Xe",131.293 );A("Rn",222 ); % Og %
% ---------------- first period elements ---> % A("H", 1.008);A("He", 4.002602);
% --- hypothetical eigth period elements ---> % A("Uue",315 );A("Ubn",299 );
Line 304 ⟶ 467:
test( 186.29499999999996, "COOH(C(CH3)2)3CH3" ); test( 350.45, "UueCl" );
end
end.</langsyntaxhighlight>
{{out}}
<pre>
Line 316 ⟶ 479:
</pre>
 
=={{header|C++AutoHotkey}}==
<syntaxhighlight lang="autohotkey">test := ["H", "H2", "H2O", "H2O2", "(HO)2", "Na2SO4", "C6H12", "COOH(C(CH3)2)3CH3", "C6H4O2(OH)4", "C27H46O"
{{trans|C#}}
, "Uue", "C6H4O2(O)H)4", "X2O"]
<lang cpp>#include <iomanip>
for i, str in test
#include <iostream>
result .= str "`t`t`t> " Chemical_calculator(str) "`n"
#include <map>
MsgBox, 262144, , % result
#include <string>
return
#include <vector>
 
Chemical_calculator(str){
std::map<std::string, double> atomicMass = {
if (RegExReplace(str, "\(([^()]|(?R))*\)")~="[()]")
{"H", 1.008},
{"He", 4.002602},return "Invalid Group"
oAtomM := {"H":1.008, "He":4.002602, "Li":6.94, "Be":9.0121831, "B":10.81, "C":12.011, "N":14.007, "O":15.999, "F":18.998403163, "Ne":20.1797
{"Li", 6.94},
, "Na":22.98976928, "Mg":24.305, "Al":26.9815385, "Si":28.085, "P":30.973761998, "S":32.06, "Cl":35.45, "K":39.0983, "Ar":39.948, "Ca":40.078
{"Be", 9.0121831},
, "Sc":44.955908, "Ti":47.867, "V":50.9415, "Cr":51.9961, "Mn":54.938044, "Fe":55.845, "Ni":58.6934, "Co":58.933194, "Cu":63.546, "Zn":65.38
{"B", 10.81},
, "Ga":69.723, "Ge":72.63, "As":74.921595, "Se":78.971, "Br":79.904, "Kr":83.798, "Rb":85.4678, "Sr":87.62, "Y":88.90584, "Zr":91.224, "Nb":92.90637
{"C", 12.011},
, "Mo":95.95, "Ru":101.07, "Rh":102.9055, "Pd":106.42, "Ag":107.8682, "Cd":112.414, "In":114.818, "Sn":118.71, "Sb":121.76, "I":126.90447, "Te":127.6
{"N", 14.007},
, "Xe":131.293, "Cs":132.90545196, "Ba":137.327, "La":138.90547, "Ce":140.116, "Pr":140.90766, "Nd":144.242, "Pm":145, "Sm":150.36, "Eu":151.964
{"O", 15.999},
, "Gd":157.25, "Tb":158.92535, "Dy":162.5, "Ho":164.93033, "Er":167.259, "Tm":168.93422, "Yb":173.054, "Lu":174.9668, "Hf":178.49, "Ta":180.94788
{"F", 18.998403163},
, "W":183.84, "Re":186.207, "Os":190.23, "Ir":192.217, "Pt":195.084, "Au":196.966569, "Hg":200.592, "Tl":204.38, "Pb":207.2, "Bi":208.9804, "Po":209
{"Ne", 20.1797},
, "At":210, "Rn":222, "Fr":223, "Ra":226, "Ac":227, "Pa":231.03588, "Th":232.0377, "Np":237, "U":238.02891, "Am":243, "Pu":244, "Cm":247, "Bk":247
{"Na", 22.98976928},
, "Cf":251, "Es":252, "Fm":257, "Ubn":299, "Uue":315}
{"Mg", 24.305},
{"Al", 26.9815385},
{"Si", 28.085},
{"P", 30.973761998},
{"S", 32.06},
{"Cl", 35.45},
{"Ar", 39.948},
{"K", 39.0983},
{"Ca", 40.078},
{"Sc", 44.955908},
{"Ti", 47.867},
{"V", 50.9415},
{"Cr", 51.9961},
{"Mn", 54.938044},
{"Fe", 55.845},
{"Co", 58.933194},
{"Ni", 58.6934},
{"Cu", 63.546},
{"Zn", 65.38},
{"Ga", 69.723},
{"Ge", 72.630},
{"As", 74.921595},
{"Se", 78.971},
{"Br", 79.904},
{"Kr", 83.798},
{"Rb", 85.4678},
{"Sr", 87.62},
{"Y", 88.90584},
{"Zr", 91.224},
{"Nb", 92.90637},
{"Mo", 95.95},
{"Ru", 101.07},
{"Rh", 102.90550},
{"Pd", 106.42},
{"Ag", 107.8682},
{"Cd", 112.414},
{"In", 114.818},
{"Sn", 118.710},
{"Sb", 121.760},
{"Te", 127.60},
{"I", 126.90447},
{"Xe", 131.293},
{"Cs", 132.90545196},
{"Ba", 137.327},
{"La", 138.90547},
{"Ce", 140.116},
{"Pr", 140.90766},
{"Nd", 144.242},
{"Pm", 145},
{"Sm", 150.36},
{"Eu", 151.964},
{"Gd", 157.25},
{"Tb", 158.92535},
{"Dy", 162.500},
{"Ho", 164.93033},
{"Er", 167.259},
{"Tm", 168.93422},
{"Yb", 173.054},
{"Lu", 174.9668},
{"Hf", 178.49},
{"Ta", 180.94788},
{"W", 183.84},
{"Re", 186.207},
{"Os", 190.23},
{"Ir", 192.217},
{"Pt", 195.084},
{"Au", 196.966569},
{"Hg", 200.592},
{"Tl", 204.38},
{"Pb", 207.2},
{"Bi", 208.98040},
{"Po", 209},
{"At", 210},
{"Rn", 222},
{"Fr", 223},
{"Ra", 226},
{"Ac", 227},
{"Th", 232.0377},
{"Pa", 231.03588},
{"U", 238.02891},
{"Np", 237},
{"Pu", 244},
{"Am", 243},
{"Cm", 247},
{"Bk", 247},
{"Cf", 251},
{"Es", 252},
{"Fm", 257},
{"Uue", 315},
{"Ubn", 299},
};
 
str := RegExReplace(str, "\d+", "*$0")
double evaluate(std::string s) {
swhile +=InStr(str, '[';"("){
pos := RegExMatch(str, "\(([^()]+)\)\*(\d+)", m)
m1 := RegExReplace(m1, "[A-Z]([a-z]*)", "$0*" m2)
str := RegExReplace( str, "\Q" m "\E", m1,, 1, pos)
}
str := Trim(RegExReplace(str, "[A-Z]", "+$0"), "+")
sum := 0
for i, atom in StrSplit(str, "+"){
prod := 1
for j, p in StrSplit(atom, "*")
prod *= (p~="\d+") ? p : 1
atom := RegExReplace(atom, "\*\d+")
if !oAtomM[atom]
return "Invalid atom name"
sum += oAtomM[atom] * prod
}
return str " > " sum
}</syntaxhighlight>
{{out}}
<pre>H > H > 1.008000
H2 > H*2 > 2.016000
H2O > H*2+O > 18.015000
H2O2 > H*2+O*2 > 34.014000
(HO)2 > H*2+O*2 > 34.014000
Na2SO4 > Na*2+S+O*4 > 142.035539
C6H12 > C*6+H*12 > 84.162000
COOH(C(CH3)2)3CH3 > C+O+O+H+C*3+C*3*2+H*3*2*3+C+H*3 > 186.295000
C6H4O2(OH)4 > C*6+H*4+O*2+O*4+H*4 > 176.124000
C27H46O > C*27+H*46+O > 386.664000
Uue > Uue > 315
C6H4O2(O)H)4 > Invalid Group
X2O > Invalid atom name</pre>
=={{header|C}}==
<syntaxhighlight lang="c">#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
typedef char *string;
double sum = 0.0;
 
std::string symbol;
typedef struct node_t {
std::string number;
string symbol;
double weight;
struct node_t *next;
} node;
 
node *make_node(string symbol, double weight) {
node *nptr = malloc(sizeof(node));
if (nptr) {
nptr->symbol = symbol;
nptr->weight = weight;
nptr->next = NULL;
return nptr;
}
return NULL;
}
 
void free_node(node *ptr) {
for (auto c : s) {
if ('@' <= c && c <= '['ptr) {
// @, Afree_node(ptr-Z>next);
int nptr->next = 1NULL;
if free(number != ""ptr) {;
}
n = stoi(number);
}
}
 
if (symbol != "") {
node *insert(string symbol, double weight, node *head) {
sum += atomicMass[symbol] * n;
node *nptr = make_node(symbol, weight);
}
if (cnptr->next == '[') {head;
return breaknptr;
}
}
 
symbol = c;
node *dic;
number = "";
void init() {
} else if ('a' <= c && c <= 'z') {
dic = make_node("H", 1.008);
symbol += c;
dic = insert("He", 4.002602, dic);
} else if ('0' <= c && c <= '9') {
dic = insert("Li", 6.94, dic);
number += c;
dic = insert("Be", 9.0121831, dic);
} else {
dic = insert("B", 10.81, dic);
std::string msg = "Unexpected symbol ";
dic = insert("C", 12.011, msg += cdic);
dic msg += insert("N", in14.007, molecule"dic);
dic = insert("O", 15.999, dic);
throw std::runtime_error(msg);
dic = insert("F", 18.998403163, dic);
dic = insert("Ne", 20.1797, dic);
dic = insert("Na", 22.98976928, dic);
dic = insert("Mg", 24.305, dic);
dic = insert("Al", 26.9815385, dic);
dic = insert("Si", 28.085, dic);
dic = insert("P", 30.973761998, dic);
dic = insert("S", 32.06, dic);
dic = insert("Cl", 35.45, dic);
dic = insert("Ar", 39.948, dic);
dic = insert("K", 39.0983, dic);
dic = insert("Ca", 40.078, dic);
dic = insert("Sc", 44.955908, dic);
dic = insert("Ti", 47.867, dic);
dic = insert("V", 50.9415, dic);
dic = insert("Cr", 51.9961, dic);
dic = insert("Mn", 54.938044, dic);
dic = insert("Fe", 55.845, dic);
dic = insert("Co", 58.933194, dic);
dic = insert("Ni", 58.6934, dic);
dic = insert("Cu", 63.546, dic);
dic = insert("Zn", 65.38, dic);
dic = insert("Ga", 69.723, dic);
dic = insert("Ge", 72.630, dic);
dic = insert("As", 74.921595, dic);
dic = insert("Se", 78.971, dic);
dic = insert("Br", 79.904, dic);
dic = insert("Kr", 83.798, dic);
dic = insert("Rb", 85.4678, dic);
dic = insert("Sr", 87.62, dic);
dic = insert("Y", 88.90584, dic);
dic = insert("Zr", 91.224, dic);
dic = insert("Nb", 92.90637, dic);
dic = insert("Mo", 95.95, dic);
dic = insert("Ru", 101.07, dic);
dic = insert("Rh", 102.90550, dic);
dic = insert("Pd", 106.42, dic);
dic = insert("Ag", 107.8682, dic);
dic = insert("Cd", 112.414, dic);
dic = insert("In", 114.818, dic);
dic = insert("Sn", 118.710, dic);
dic = insert("Sb", 121.760, dic);
dic = insert("Te", 127.60, dic);
dic = insert("I", 126.90447, dic);
dic = insert("Xe", 131.293, dic);
dic = insert("Cs", 132.90545196, dic);
dic = insert("Ba", 137.327, dic);
dic = insert("La", 138.90547, dic);
dic = insert("Ce", 140.116, dic);
dic = insert("Pr", 140.90766, dic);
dic = insert("Nd", 144.242, dic);
dic = insert("Pm", 145, dic);
dic = insert("Sm", 150.36, dic);
dic = insert("Eu", 151.964, dic);
dic = insert("Gd", 157.25, dic);
dic = insert("Tb", 158.92535, dic);
dic = insert("Dy", 162.500, dic);
dic = insert("Ho", 164.93033, dic);
dic = insert("Er", 167.259, dic);
dic = insert("Tm", 168.93422, dic);
dic = insert("Yb", 173.054, dic);
dic = insert("Lu", 174.9668, dic);
dic = insert("Hf", 178.49, dic);
dic = insert("Ta", 180.94788, dic);
dic = insert("W", 183.84, dic);
dic = insert("Re", 186.207, dic);
dic = insert("Os", 190.23, dic);
dic = insert("Ir", 192.217, dic);
dic = insert("Pt", 195.084, dic);
dic = insert("Au", 196.966569, dic);
dic = insert("Hg", 200.592, dic);
dic = insert("Tl", 204.38, dic);
dic = insert("Pb", 207.2, dic);
dic = insert("Bi", 208.98040, dic);
dic = insert("Po", 209, dic);
dic = insert("At", 210, dic);
dic = insert("Rn", 222, dic);
dic = insert("Fr", 223, dic);
dic = insert("Ra", 226, dic);
dic = insert("Ac", 227, dic);
dic = insert("Th", 232.0377, dic);
dic = insert("Pa", 231.03588, dic);
dic = insert("U", 238.02891, dic);
dic = insert("Np", 237, dic);
dic = insert("Pu", 244, dic);
dic = insert("Am", 243, dic);
dic = insert("Cm", 247, dic);
dic = insert("Bk", 247, dic);
dic = insert("Cf", 251, dic);
dic = insert("Es", 252, dic);
dic = insert("Fm", 257, dic);
dic = insert("Uue", 315, dic);
dic = insert("Ubn", 299, dic);
}
 
double lookup(string symbol) {
for (node *ptr = dic; ptr; ptr = ptr->next) {
if (strcmp(symbol, ptr->symbol) == 0) {
return ptr->weight;
}
}
 
printf("symbol not found: %s\n", symbol);
return sum;
return 0.0;
}
 
double total(double mass, int count) {
std::string replaceFirst(const std::string &text, const std::string &search, const std::string &replace) {
autoif pos(count => text.find(search0); {
return mass * count;
if (pos == std::string::npos) {
return text;
}
return mass;
}
 
double total_s(string sym, int count) {
auto beg = text.substr(0, pos);
autodouble endmass = text.substrlookup(pos + search.length()sym);
return begtotal(mass, + replace + endcount);
}
 
double evaluate_c(string expr, size_t *pos, double mass) {
std::string replaceParens(std::string s) {
charint lettercount = 'a'0;
if (expr[*pos] < '0' || '9' < expr[*pos]) {
while (true) {
printf("expected to find a count, saw the character: %c\n", expr[*pos]);
auto start = s.find("(");
}
if (start == std::string::npos) {
for (; expr[*pos]; (*pos)++) {
char c = expr[*pos];
if ('0' <= c && c <= '9') {
count = count * 10 + c - '0';
} else {
break;
}
}
return total(mass, count);
}
 
double evaluate_p(string expr, size_t limit, size_t *pos) {
for (size_t i = start + 1; i < s.length(); i++) {
char if (ssym[i4] == ')') {;
int sym_pos = 0;
auto expr = s.substr(start + 1, i - start - 1);
int std::string symbolcount = "@"0;
double sum symbol += letter0.0;
 
auto search = s.substr(start, i + 1 - start);
for (; *pos < limit && expr[*pos]; (*pos)++) {
s = replaceFirst(s, search, symbol);
char c = atomicMassexpr[symbol*pos] = evaluate(expr);
if ('A' <= c && c <= 'Z') letter++;{
if (sym_pos > 0) break;{
sum += total_s(sym, count);
sym_pos = 0;
count = 0;
}
if (ssym[isym_pos++] == '(') {c;
startsym[sym_pos] = i0;
} else if ('a' <= c && c continue;<= 'z') {
sym[sym_pos++] = c;
sym[sym_pos] = 0;
} else if ('0' <= c && c <= '9') {
count = count * 10 + c - '0';
} else if (c == '(') {
if (sym_pos > 0) {
sum += total_s(sym, count);
sym_pos = 0;
count = 0;
}
 
(*pos)++; // skip past the paren
double mass = evaluate_p(expr, limit, pos);
 
sum += evaluate_c(expr, pos, mass);
(*pos)--; // neutralize the position increment
} else if (c == ')') {
if (sym_pos > 0) {
sum += total_s(sym, count);
sym_pos = 0;
count = 0;
}
 
(*pos)++;
return sum;
} else {
printf("Unexpected character encountered: %c\n", c);
}
}
 
return s;
if (sym_pos > 0) {
sum += total_s(sym, count);
}
return sum;
}
 
double evaluate(string expr) {
size_t limit = strlen(expr);
size_t pos = 0;
return evaluate_p(expr, limit, &pos);
}
 
void test(string expr) {
double mass = evaluate(expr);
printf("%17s -> %7.3f\n", expr, mass);
}
 
int main() {
init();
std::vector<std::string> molecules = {
 
"H", "H2", "H2O", "H2O2", "(HO)2", "Na2SO4", "C6H12",
test("H");
"COOH(C(CH3)2)3CH3", "C6H4O2(OH)4", "C27H46O", "Uue"
}test("H2");
test("H2O");
for (auto molecule : molecules) {
test("H2O2");
auto mass = evaluate(replaceParens(molecule));
test("(HO)2");
std::cout << std::setw(17) << molecule << " -> " << std::setw(7) << std::fixed << std::setprecision(3) << mass << '\n';
}test("Na2SO4");
test("C6H12");
test("COOH(C(CH3)2)3CH3");
test("C6H4O2(OH)4");
test("C27H46O");
test("Uue");
 
free_node(dic);
dic = NULL;
return 0;
}</langsyntaxhighlight>
{{out}}
<pre> H -> 1.008
Line 528 ⟶ 811:
C27H46O -> 386.664
Uue -> 315.000</pre>
=={{header|C sharp|C#}}==
 
=={{header|C#}}==
{{trans|D}}
<langsyntaxhighlight lang="csharp">using System;
using System.Collections.Generic;
using System.Linq;
Line 721 ⟶ 1,003:
}
}
}</langsyntaxhighlight>
{{out}}
<pre> H -> 1.008
Line 734 ⟶ 1,016:
C27H46O -> 386.664
Uue -> 315.000</pre>
=={{header|C++}}==
{{trans|C#}}
<syntaxhighlight lang="cpp">#include <iomanip>
#include <iostream>
#include <map>
#include <string>
#include <vector>
 
std::map<std::string, double> atomicMass = {
{"H", 1.008},
{"He", 4.002602},
{"Li", 6.94},
{"Be", 9.0121831},
{"B", 10.81},
{"C", 12.011},
{"N", 14.007},
{"O", 15.999},
{"F", 18.998403163},
{"Ne", 20.1797},
{"Na", 22.98976928},
{"Mg", 24.305},
{"Al", 26.9815385},
{"Si", 28.085},
{"P", 30.973761998},
{"S", 32.06},
{"Cl", 35.45},
{"Ar", 39.948},
{"K", 39.0983},
{"Ca", 40.078},
{"Sc", 44.955908},
{"Ti", 47.867},
{"V", 50.9415},
{"Cr", 51.9961},
{"Mn", 54.938044},
{"Fe", 55.845},
{"Co", 58.933194},
{"Ni", 58.6934},
{"Cu", 63.546},
{"Zn", 65.38},
{"Ga", 69.723},
{"Ge", 72.630},
{"As", 74.921595},
{"Se", 78.971},
{"Br", 79.904},
{"Kr", 83.798},
{"Rb", 85.4678},
{"Sr", 87.62},
{"Y", 88.90584},
{"Zr", 91.224},
{"Nb", 92.90637},
{"Mo", 95.95},
{"Ru", 101.07},
{"Rh", 102.90550},
{"Pd", 106.42},
{"Ag", 107.8682},
{"Cd", 112.414},
{"In", 114.818},
{"Sn", 118.710},
{"Sb", 121.760},
{"Te", 127.60},
{"I", 126.90447},
{"Xe", 131.293},
{"Cs", 132.90545196},
{"Ba", 137.327},
{"La", 138.90547},
{"Ce", 140.116},
{"Pr", 140.90766},
{"Nd", 144.242},
{"Pm", 145},
{"Sm", 150.36},
{"Eu", 151.964},
{"Gd", 157.25},
{"Tb", 158.92535},
{"Dy", 162.500},
{"Ho", 164.93033},
{"Er", 167.259},
{"Tm", 168.93422},
{"Yb", 173.054},
{"Lu", 174.9668},
{"Hf", 178.49},
{"Ta", 180.94788},
{"W", 183.84},
{"Re", 186.207},
{"Os", 190.23},
{"Ir", 192.217},
{"Pt", 195.084},
{"Au", 196.966569},
{"Hg", 200.592},
{"Tl", 204.38},
{"Pb", 207.2},
{"Bi", 208.98040},
{"Po", 209},
{"At", 210},
{"Rn", 222},
{"Fr", 223},
{"Ra", 226},
{"Ac", 227},
{"Th", 232.0377},
{"Pa", 231.03588},
{"U", 238.02891},
{"Np", 237},
{"Pu", 244},
{"Am", 243},
{"Cm", 247},
{"Bk", 247},
{"Cf", 251},
{"Es", 252},
{"Fm", 257},
{"Uue", 315},
{"Ubn", 299},
};
 
double evaluate(std::string s) {
s += '[';
 
double sum = 0.0;
std::string symbol;
std::string number;
 
for (auto c : s) {
if ('@' <= c && c <= '[') {
// @, A-Z
int n = 1;
if (number != "") {
n = stoi(number);
}
if (symbol != "") {
sum += atomicMass[symbol] * n;
}
if (c == '[') {
break;
}
symbol = c;
number = "";
} else if ('a' <= c && c <= 'z') {
symbol += c;
} else if ('0' <= c && c <= '9') {
number += c;
} else {
std::string msg = "Unexpected symbol ";
msg += c;
msg += " in molecule";
throw std::runtime_error(msg);
}
}
 
return sum;
}
 
std::string replaceFirst(const std::string &text, const std::string &search, const std::string &replace) {
auto pos = text.find(search);
if (pos == std::string::npos) {
return text;
}
 
auto beg = text.substr(0, pos);
auto end = text.substr(pos + search.length());
return beg + replace + end;
}
 
std::string replaceParens(std::string s) {
char letter = 'a';
while (true) {
auto start = s.find("(");
if (start == std::string::npos) {
break;
}
 
for (size_t i = start + 1; i < s.length(); i++) {
if (s[i] == ')') {
auto expr = s.substr(start + 1, i - start - 1);
std::string symbol = "@";
symbol += letter;
auto search = s.substr(start, i + 1 - start);
s = replaceFirst(s, search, symbol);
atomicMass[symbol] = evaluate(expr);
letter++;
break;
}
if (s[i] == '(') {
start = i;
continue;
}
}
}
return s;
}
 
int main() {
std::vector<std::string> molecules = {
"H", "H2", "H2O", "H2O2", "(HO)2", "Na2SO4", "C6H12",
"COOH(C(CH3)2)3CH3", "C6H4O2(OH)4", "C27H46O", "Uue"
};
for (auto molecule : molecules) {
auto mass = evaluate(replaceParens(molecule));
std::cout << std::setw(17) << molecule << " -> " << std::setw(7) << std::fixed << std::setprecision(3) << mass << '\n';
}
 
return 0;
}</syntaxhighlight>
{{out}}
<pre> H -> 1.008
H2 -> 2.016
H2O -> 18.015
H2O2 -> 34.014
(HO)2 -> 34.014
Na2SO4 -> 142.036
C6H12 -> 84.162
COOH(C(CH3)2)3CH3 -> 186.295
C6H4O2(OH)4 -> 176.124
C27H46O -> 386.664
Uue -> 315.000</pre>
=={{header|CoffeeScript}}==
===No Regular Expression===
<langsyntaxhighlight lang="coffeescript">ATOMIC_MASS = {H:1.008,C:12.011,O:15.999,Na:22.98976928,S:32.06,Uue:315}
 
molar_mass = (s) ->
Line 768 ⟶ 1,261:
assert 176.124, molar_mass 'C6H4O2(OH)4' # Vitamin C
assert 386.664, molar_mass 'C27H46O' # Cholesterol
assert 315, molar_mass 'Uue'</langsyntaxhighlight>
 
===Regular Expression===
{{trans|Julia}}
<langsyntaxhighlight lang="coffeescript">ATOMIC_MASS = {H:1.008,C:12.011,O:15.999,Na:22.98976928,S:32.06,Uue:315}
 
mul = (match, p1, offset, string) -> '*' + p1
Line 794 ⟶ 1,287:
assert 176.124, molar_mass('C6H4O2(OH)4') # Vitamin C
assert 386.664, molar_mass('C27H46O') # Cholesterol
assert 315, molar_mass('Uue')</langsyntaxhighlight>
 
=={{header|D}}==
{{trans|Go}}
<langsyntaxhighlight lang="d">import std.array;
import std.conv;
import std.format;
Line 979 ⟶ 1,471:
}
writeln(atomicMass);
}</langsyntaxhighlight>
{{out}}
<pre> H -> 1.008
Line 993 ⟶ 1,485:
Uue -> 315.000</pre>
 
=={{header|Delphi}}==
{{trans|Go}}
<syntaxhighlight lang="delphi">
program ChemicalCalculator;
 
{$APPTYPE CONSOLE}
 
{$R *.res}
 
uses
System.SysUtils,
System.Generics.Collections;
 
{$I AtomicMass.inc }
 
type
TAtomicMass = class(TDictionary<string, Double>)
public
constructor Create(Keys: array of string; Values: array of Double); overload;
end;
 
{ TAtomicMass }
 
constructor TAtomicMass.Create(Keys: array of string; Values: array of Double);
var
i: Integer;
begin
inherited Create;
 
Assert(length(Keys) = Length(Values), 'Keys and values must have the same size');
if Length(Keys) = 0 then
exit;
 
for i := 0 to High(Keys) do
Add(Keys[i], Values[i]);
end;
 
var
AtomicMassData: TAtomicMass;
 
function Evaluate(s: string): Double;
var
sum: Double;
symbol: string;
number: string;
c: char;
i, n: Integer;
begin
s := s + '[';
symbol := '';
number := '';
 
for i := 1 to s.Length do
begin
c := s[i];
if ('@' <= c) and (c <= '[') then
begin
n := 1;
if not number.IsEmpty then
n := StrToInt(number);
if not symbol.IsEmpty then
sum := sum + AtomicMassData[symbol] * n;
if c = '[' then
Break;
symbol := c;
number := '';
Continue;
end;
 
if ('a' <= c) and (c <= 'z') then
begin
symbol := symbol + c;
Continue;
end;
 
if ('0' <= c) and (c <= '9') then
begin
number := number + c;
Continue;
end;
 
raise Exception.Create('Unexpected symbol ' + c + ' in molecule');
end;
Result := sum;
end;
 
function ReplaceFirst(text, search, replace: string): string;
var
pos: Integer;
begin
pos := text.IndexOf(search);
if (pos < 0) then
Exit(text);
Result := text.Substring(0, pos) + replace + text.Substring(pos + search.Length);
end;
 
function ReplaceParens(s: string): string;
var
letter: Char;
start: Integer;
i: Integer;
expr, symbol: string;
begin
letter := 's';
while True do
begin
start := s.IndexOf('(');
if (start = -1) then
Break;
 
for i := start + 1 to s.Length - 1 do
begin
if s[i + 1] = ')' then
begin
expr := s.Substring(start + 1, i - start - 1);
symbol := '@' + letter;
s := ReplaceFirst(s, s.Substring(start, i + 1 - start), symbol);
if not (AtomicMassData.ContainsKey(symbol)) then
AtomicMassData.Add(symbol, Evaluate(expr))
else
AtomicMassData[symbol] := Evaluate(expr);
inc(letter);
Break;
end;
 
if (s[i + 1] = '(') then
start := i;
end;
end;
Result := s;
end;
 
 
var
molecules: array of string;
i: Integer;
mass: Double;
 
begin
molecules := ['H', 'H2', 'H2O', 'H2O2', '(HO)2', 'Na2SO4', 'C6H12',
'COOH(C(CH3)2)3CH3', 'C6H4O2(OH)4', 'C27H46O', 'Uue'];
AtomicMassData := TAtomicMass.Create(ATOMIC_MASS_SYMBOL, ATOMIC_MASS_VALUE);
 
for i := 0 to 10 do
begin
mass := Evaluate(ReplaceParens(molecules[i]));
Writeln(format('%17s -> %7s', [molecules[i], FormatFloat('####.000',mass)]));
end;
 
AtomicMassData.Free;
readln;
end.
</syntaxhighlight>
Include file with Atomic Mass Constants ('''AtomicMass.inc''').
<syntaxhighlight lang="delphi">
const
ATOMIC_MASS_SIZE = 101;
ATOMIC_MASS_SYMBOL: array[0..ATOMIC_MASS_SIZE - 1] of string = ('H', 'He',
'Li', 'Be', 'B', 'C', 'N', 'O', 'F', 'Ne', 'Na', 'Mg', 'Al', 'Si', 'P', 'S',
'Cl', 'Ar', 'K', 'Ca', 'Sc', 'Ti', 'V', 'Cr', 'Mn', 'Fe', 'Co', 'Ni', 'Cu',
'Zn', 'Ga', 'Ge', 'As', 'Se', 'Br', 'Kr', 'Rb', 'Sr', 'Y', 'Zr', 'Nb', 'Mo',
'Ru', 'Rh', 'Pd', 'Ag', 'Cd', 'In', 'Sn', 'Sb', 'Te', 'I', 'Xe', 'Cs', 'Ba',
'La', 'Ce', 'Pr', 'Nd', 'Pm', 'Sm', 'Eu', 'Gd', 'Tb', 'Dy', 'Ho', 'Er', 'Tm',
'Yb', 'Lu', 'Hf', 'Ta', 'W', 'Re', 'Os', 'Ir', 'Pt', 'Au', 'Hg', 'Tl', 'Pb',
'Bi', 'Po', 'At', 'Rn', 'Fr', 'Ra', 'Ac', 'Th', 'Pa', 'U', 'Np', 'Pu', 'Am',
'Cm', 'Bk', 'Cf', 'Es', 'Fm', 'Uue', 'Ubn');
 
ATOMIC_MASS_VALUE: array[0..ATOMIC_MASS_SIZE - 1] of double = (1.008, 4.002602,
6.94, 9.0121831, 10.81, 12.011, 14.007, 15.999, 18.998403163, 20.1797,
22.98976928, 24.305, 26.9815385, 28.085, 30.973761998, 32.06, 35.45, 39.948,
39.0983, 40.078, 44.955908, 47.867, 50.9415, 51.9961, 54.938044, 55.845,
58.933194, 58.6934, 63.546, 65.38, 69.723, 72.630, 74.921595, 78.971, 79.904,
83.798, 85.4678, 87.62, 88.90584, 91.224, 92.90637, 95.95, 101.07, 102.90550,
106.42, 107.8682, 112.414, 114.818, 118.710, 121.760, 127.60, 126.90447,
131.293, 132.90545196, 137.327, 138.90547, 140.116, 140.90766, 144.242, 145,
150.36, 151.964, 157.25, 158.92535, 162.500, 164.93033, 167.259, 168.93422,
173.054, 174.9668, 178.49, 180.94788, 183.84, 186.207, 190.23, 192.217,
195.084, 196.966569, 200.592, 204.38, 207.2, 208.98040, 209, 210, 222, 223,
226, 227, 232.0377, 231.03588, 238.02891, 237, 244, 243, 247, 247, 251, 252,
257, 315, 299);
</syntaxhighlight>
=={{header|Factor}}==
{{works with|Factor|0.98}}
<langsyntaxhighlight lang="factor">USING: assocs compiler.units definitions grouping infix.parser
infix.private kernel math.functions math.parser multiline
peg.ebnf qw sequences splitting strings words words.constant ;
Line 1,079 ⟶ 1,752:
} [ molar-mass 1e-5 approx-assert= ] assoc-each ;
 
MAIN: chemical-calculator-demo</langsyntaxhighlight>
 
No assertion errors.
Line 1,085 ⟶ 1,758:
=={{header|Fōrmulæ}}==
 
{{FormulaeEntry|page=https://formulae.org/?script=examples/Chemical_calculator}}
In [http://wiki.formulae.org/Chemical_Calculator this] page you can see the solution of this task.
 
'''Solution'''
 
Fōrmulæ has a module for chemistry. Notice that it is not a library, it effectively adds chemical elements as first class citizens to the language, and useful functions that operate with them, for example, to get their atomic masses.
 
There is an expression for a '''homonuclear compound''', a compound made from the union of several atoms of the same element, such as O<sub>2</sub>
 
There is also an expression for a '''heteronuclear compound''', a compound made from the union of several atoms of different elements, such as NaCl
 
[[File: Fōrmulæ - Chemical calculator 01.png]]
 
'''Notes'''
 
* The Tag(Expression) expression retrieves the tag of an expression. For example, when it is called on an homonuclear compound expression, it retrieves the string expression representing the string "Chemistry.HomonuclearCompound"
 
* The |Expression| retrieves the cardinality of the expression, this is, the number of subexpressions it has. If the expression is a heteronuclear compound it gives the number of elements being composed.
 
* If the expression given as parameter is a heteronuclear compound expression, the molar mass is the sum of the molar masses of each component. Note that this function is recursively called.
 
* If the expression given as parameter is a homonuclear compound expression, the molar mass is the product of the number of the group (the second component) and the molar mass of the expression (the first component). Note that this function is recursively called.
 
* Elsewhere, the result is the call of the GetAtomicMass(Expression) with the expression given as parameter.
 
'''Test cases'''
 
[[File: Fōrmulæ - Chemical calculator 02.png]]
 
[[File: Fōrmulæ - Chemical calculator 03.png]]
 
'''Using it symbolically'''
 
Fōrmulæ is a symbolic language. Although chemical elements expressions are intended to be used to create chemical formulae, other expressions can be used, specially symbols, as in the following examples:
 
Example 1. Using a symbol to denote and unspecified number of repetitions in a homonuclear compound expression. For this exercise, n is a free symbol (a symbol with no associated value).
 
[[File: Fōrmulæ - Chemical calculator 04.png]]
 
[[File: Fōrmulæ - Chemical calculator 05.png]]
 
Example 2. Using a symbol to denote an unspecified chemical element. For this exercise, X is a free symbol (a symbol with no associated value).
 
[[File: Fōrmulæ - Chemical calculator 06.png]]
 
[[File: Fōrmulæ - Chemical calculator 07.png]]
 
Example 3. Using symbols to denote an unspecified chemical element and an unspecified number of repetitions. For this exercise, X and n are free symbols (symbols with no associated values).
 
[[File: Fōrmulæ - Chemical calculator 08.png]]
 
[[File: Fōrmulæ - Chemical calculator 09.png]]
 
Example 4. Using symbols to denote different unspecified chemical elements. For this exercise, X, Y and Z are free symbols (symbols with no associated values).
 
[[File: Fōrmulæ - Chemical calculator 10.png]]
 
[[File: Fōrmulæ - Chemical calculator 11.png]]
 
Example 5. Other combinations. For this exercise, X, Y, Z, n and m are free symbols (symbols with no associated values).
 
[[File: Fōrmulæ - Chemical calculator 12.png]]
Fōrmulæ programs are not textual, visualization/edition of programs is done showing/manipulating structures but not text ([http://wiki.formulae.org/Editing_F%C5%8Drmul%C3%A6_expressions more info]). Moreover, there can be multiple visual representations of the same program. Even though it is possible to have textual representation &mdash;i.e. XML, JSON&mdash; they are intended for transportation effects more than visualization and edition.
 
[[File: Fōrmulæ - Chemical calculator 13.png]]
The option to show Fōrmulæ programs and their results is showing images. Unfortunately images cannot be uploaded in Rosetta Code.
 
=={{header|Go}}==
This doesn't use regular expressions, RPN or eval (which Go doesn't have). It's just a simple molar mass evaluator written from scratch.
<langsyntaxhighlight lang="go">package main
 
import (
Line 1,271 ⟶ 2,002:
fmt.Printf("%17s -> %7.3f\n", molecule, mass)
}
}</langsyntaxhighlight>
 
{{out}}
Line 1,286 ⟶ 2,017:
C27H46O -> 386.664
Uue -> 315.000
</pre>
=={{header|Groovy}}==
{{trans|Java}}
<syntaxhighlight lang="groovy">import java.util.regex.Pattern
 
class ChemicalCalculator {
private static final Map<String, Double> ATOMIC_MASS = new HashMap<>()
 
static {
ATOMIC_MASS.put("H", 1.008)
ATOMIC_MASS.put("He", 4.002602)
ATOMIC_MASS.put("Li", 6.94)
ATOMIC_MASS.put("Be", 9.0121831)
ATOMIC_MASS.put("B", 10.81)
ATOMIC_MASS.put("C", 12.011)
ATOMIC_MASS.put("N", 14.007)
ATOMIC_MASS.put("O", 15.999)
ATOMIC_MASS.put("F", 18.998403163)
ATOMIC_MASS.put("Ne", 20.1797)
ATOMIC_MASS.put("Na", 22.98976928)
ATOMIC_MASS.put("Mg", 24.305)
ATOMIC_MASS.put("Al", 26.9815385)
ATOMIC_MASS.put("Si", 28.085)
ATOMIC_MASS.put("P", 30.973761998)
ATOMIC_MASS.put("S", 32.06)
ATOMIC_MASS.put("Cl", 35.45)
ATOMIC_MASS.put("Ar", 39.948)
ATOMIC_MASS.put("K", 39.0983)
ATOMIC_MASS.put("Ca", 40.078)
ATOMIC_MASS.put("Sc", 44.955908)
ATOMIC_MASS.put("Ti", 47.867)
ATOMIC_MASS.put("V", 50.9415)
ATOMIC_MASS.put("Cr", 51.9961)
ATOMIC_MASS.put("Mn", 54.938044)
ATOMIC_MASS.put("Fe", 55.845)
ATOMIC_MASS.put("Co", 58.933194)
ATOMIC_MASS.put("Ni", 58.6934)
ATOMIC_MASS.put("Cu", 63.546)
ATOMIC_MASS.put("Zn", 65.38)
ATOMIC_MASS.put("Ga", 69.723)
ATOMIC_MASS.put("Ge", 72.630)
ATOMIC_MASS.put("As", 74.921595)
ATOMIC_MASS.put("Se", 78.971)
ATOMIC_MASS.put("Br", 79.904)
ATOMIC_MASS.put("Kr", 83.798)
ATOMIC_MASS.put("Rb", 85.4678)
ATOMIC_MASS.put("Sr", 87.62)
ATOMIC_MASS.put("Y", 88.90584)
ATOMIC_MASS.put("Zr", 91.224)
ATOMIC_MASS.put("Nb", 92.90637)
ATOMIC_MASS.put("Mo", 95.95)
ATOMIC_MASS.put("Ru", 101.07)
ATOMIC_MASS.put("Rh", 102.90550)
ATOMIC_MASS.put("Pd", 106.42)
ATOMIC_MASS.put("Ag", 107.8682)
ATOMIC_MASS.put("Cd", 112.414)
ATOMIC_MASS.put("In", 114.818)
ATOMIC_MASS.put("Sn", 118.710)
ATOMIC_MASS.put("Sb", 121.760)
ATOMIC_MASS.put("Te", 127.60)
ATOMIC_MASS.put("I", 126.90447)
ATOMIC_MASS.put("Xe", 131.293)
ATOMIC_MASS.put("Cs", 132.90545196)
ATOMIC_MASS.put("Ba", 137.327)
ATOMIC_MASS.put("La", 138.90547)
ATOMIC_MASS.put("Ce", 140.116)
ATOMIC_MASS.put("Pr", 140.90766)
ATOMIC_MASS.put("Nd", 144.242)
ATOMIC_MASS.put("Pm", 145.0)
ATOMIC_MASS.put("Sm", 150.36)
ATOMIC_MASS.put("Eu", 151.964)
ATOMIC_MASS.put("Gd", 157.25)
ATOMIC_MASS.put("Tb", 158.92535)
ATOMIC_MASS.put("Dy", 162.500)
ATOMIC_MASS.put("Ho", 164.93033)
ATOMIC_MASS.put("Er", 167.259)
ATOMIC_MASS.put("Tm", 168.93422)
ATOMIC_MASS.put("Yb", 173.054)
ATOMIC_MASS.put("Lu", 174.9668)
ATOMIC_MASS.put("Hf", 178.49)
ATOMIC_MASS.put("Ta", 180.94788)
ATOMIC_MASS.put("W", 183.84)
ATOMIC_MASS.put("Re", 186.207)
ATOMIC_MASS.put("Os", 190.23)
ATOMIC_MASS.put("Ir", 192.217)
ATOMIC_MASS.put("Pt", 195.084)
ATOMIC_MASS.put("Au", 196.966569)
ATOMIC_MASS.put("Hg", 200.592)
ATOMIC_MASS.put("Tl", 204.38)
ATOMIC_MASS.put("Pb", 207.2)
ATOMIC_MASS.put("Bi", 208.98040)
ATOMIC_MASS.put("Po", 209.0)
ATOMIC_MASS.put("At", 210.0)
ATOMIC_MASS.put("Rn", 222.0)
ATOMIC_MASS.put("Fr", 223.0)
ATOMIC_MASS.put("Ra", 226.0)
ATOMIC_MASS.put("Ac", 227.0)
ATOMIC_MASS.put("Th", 232.0377)
ATOMIC_MASS.put("Pa", 231.03588)
ATOMIC_MASS.put("U", 238.02891)
ATOMIC_MASS.put("Np", 237.0)
ATOMIC_MASS.put("Pu", 244.0)
ATOMIC_MASS.put("Am", 243.0)
ATOMIC_MASS.put("Cm", 247.0)
ATOMIC_MASS.put("Bk", 247.0)
ATOMIC_MASS.put("Cf", 251.0)
ATOMIC_MASS.put("Es", 252.0)
ATOMIC_MASS.put("Fm", 257.0)
ATOMIC_MASS.put("Uue", 315.0)
ATOMIC_MASS.put("Ubn", 299.0)
}
 
private static double evaluate(String s) {
String sym = s + "["
double sum = 0.0
StringBuilder symbol = new StringBuilder()
String number = ""
for (int i = 0; i < sym.length(); ++i) {
char c = sym.charAt(i)
if (('@' as char) <= c && c <= ('[' as char)) {
// @, A-Z, [
int n = 1
if (!number.isEmpty()) {
n = Integer.parseInt(number)
}
if (symbol.length() > 0) {
sum += ATOMIC_MASS.getOrDefault(symbol.toString(), 0.0) * n
}
if (c == '[' as char) {
break
}
symbol = new StringBuilder(String.valueOf(c))
number = ""
} else if (('a' as char) <= c && c <= ('z' as char)) {
symbol.append(c)
} else if (('0' as char) <= c && c <= ('9' as char)) {
number += c
} else {
throw new RuntimeException("Unexpected symbol " + c + " in molecule")
}
}
return sum
}
 
private static String replaceParens(String s) {
char letter = 'a'
String si = s
while (true) {
int start = si.indexOf('(')
if (start == -1) {
break
}
 
for (int i = start + 1; i < si.length(); ++i) {
if (si.charAt(i) == (')' as char)) {
String expr = si.substring(start + 1, i)
String symbol = "@" + letter
String pattern = Pattern.quote(si.substring(start, i + 1))
si = si.replaceFirst(pattern, symbol)
ATOMIC_MASS.put(symbol, evaluate(expr))
letter++
break
}
if (si.charAt(i) == ('(' as char)) {
start = i
}
}
}
return si
}
 
static void main(String[] args) {
List<String> molecules = [
"H", "H2", "H2O", "H2O2", "(HO)2", "Na2SO4", "C6H12",
"COOH(C(CH3)2)3CH3", "C6H4O2(OH)4", "C27H46O", "Uue"
]
for (String molecule : molecules) {
double mass = evaluate(replaceParens(molecule))
printf("%17s -> %7.3f\n", molecule, mass)
}
}
}</syntaxhighlight>
{{out}}
<pre> H -> 1.008
H2 -> 2.016
H2O -> 18.015
H2O2 -> 34.014
(HO)2 -> 34.014
Na2SO4 -> 142.036
C6H12 -> 84.162
COOH(C(CH3)2)3CH3 -> 186.295
C6H4O2(OH)4 -> 176.124
C27H46O -> 386.664
Uue -> 315.000</pre>
=={{header|Haskell}}==
Create a set of parsers for molecular formulae and their subparts. The parsers maintain a running total of the mass parsed so far. Use a '''Reader''' monad to store a map from atom names to their masses. The contents of the map are read from the file '''chemcalc_masses.in''', not shown here.
<syntaxhighlight lang="haskell">import Control.Monad (forM_)
import Control.Monad.Reader (Reader, ask, runReader)
import Data.Bifunctor (first)
import Data.Map (Map)
import qualified Data.Map as M
import Data.Void (Void)
import System.Environment (getArgs)
import System.IO (IOMode(ReadMode), withFile)
import System.IO.Strict (hGetContents)
import Text.Megaparsec (ParsecT, (<|>), between, errorBundlePretty, getOffset,
many, option, runParserT, some, setOffset)
import Text.Megaparsec.Char (char, lowerChar, upperChar)
import Text.Megaparsec.Char.Lexer (decimal)
import Text.Printf (printf)
 
type Masses = Map String Double
type ChemParser = ParsecT Void String (Reader Masses) Double
 
-- Parse the formula of a molecule, returning the latter's total mass.
molecule :: ChemParser
molecule = sum <$> some (atomGroup <|> atom)
 
-- Parse an atom group, optionally followed by its count, returning its total
-- mass.
atomGroup :: ChemParser
atomGroup = mul <$> between (char '(') (char ')') molecule <*> option 1 decimal
 
-- Parse an atom name, optionally followed by a count, returning its total mass.
atom :: ChemParser
atom = mul <$> atomMass <*> option 1 decimal
 
-- Parse an atom name, returning its mass. Fail if the name is unknown.
atomMass :: ChemParser
atomMass = do
off <- getOffset
masses <- ask
atomName <- (:) <$> upperChar <*> many lowerChar
case M.lookup atomName masses of
Nothing -> setOffset off >> fail "invalid atom name starting here"
Just mass -> return mass
 
-- Given a molecular formula and a map from atom names to their masses, return
-- the the total molar mass, or an error message if the formula can't be parsed.
molarMass :: String -> String -> Masses -> Either String Double
molarMass file formula = first errorBundlePretty . runChemParser
where runChemParser = runReader (runParserT molecule file formula)
 
-- Read from a file the map from atom names to their masses.
getMasses :: FilePath -> IO Masses
getMasses path = withFile path ReadMode (fmap read . hGetContents)
 
mul :: Double -> Int -> Double
mul s n = s * fromIntegral n
 
main :: IO ()
main = do
masses <- getMasses "chemcalc_masses.in"
molecs <- getArgs
forM_ molecs $ \molec -> do
printf "%-20s" molec
case molarMass "<stdin>" molec masses of
Left err -> printf "\n%s" err
Right mass -> printf " %.4f\n" mass
</syntaxhighlight>
{{out}}
<pre>
H 1.0080
H2 2.0160
H2O 18.0150
H2O2 34.0140
(HO)2 34.0140
Na2SO4 142.0355
C6H12 84.1620
COOH(C(CH3)2)3CH3 186.2950
C6H4O2(OH)4 176.1240
C27H46O 386.6640
Uue 315.0000
(HOz)2
<stdin>:1:3:
|
1 | (HOz)2
| ^
invalid atom name starting here
</pre>
=={{header|J}}==
 
This could be done a bit more concisely, but it's not clear that that would be an advantage here.
 
<syntaxhighlight lang=J>do{{)n
H: 1.008, He: 4.002602, Li: 6.94, Be: 9.0121831,
B: 10.81, C: 12.011, N: 14.007, O: 15.999,
F: 18.998403163, Ne: 20.1797, Na: 22.98976928, Mg: 24.305,
Al: 26.9815385, Si: 28.085, P: 30.973761998, S: 32.06,
Cl: 35.45, K: 39.0983, Ar: 39.948, Ca: 40.078,
Sc: 44.955908, Ti: 47.867, V: 50.9415, Cr: 51.9961,
Mn: 54.938044, Fe: 55.845, Ni: 58.6934, Co: 58.933194,
Cu: 63.546, Zn: 65.38, Ga: 69.723, Ge: 72.63,
As: 74.921595, Se: 78.971, Br: 79.904, Kr: 83.798,
Rb: 85.4678, Sr: 87.62, Y: 88.90584, Zr: 91.224,
Nb: 92.90637, Mo: 95.95, Ru: 101.07, Rh: 102.9055,
Pd: 106.42, Ag: 107.8682, Cd: 112.414, In: 114.818,
Sn: 118.71, Sb: 121.76, I: 126.90447, Te: 127.6,
Xe: 131.293, Cs: 132.90545196, Ba: 137.327, La: 138.90547,
Ce: 140.116, Pr: 140.90766, Nd: 144.242, Pm: 145,
Sm: 150.36, Eu: 151.964, Gd: 157.25, Tb: 158.92535,
Dy: 162.5, Ho: 164.93033, Er: 167.259, Tm: 168.93422,
Yb: 173.054, Lu: 174.9668, Hf: 178.49, Ta: 180.94788,
W: 183.84, Re: 186.207, Os: 190.23, Ir: 192.217,
Pt: 195.084, Au: 196.966569, Hg: 200.592, Tl: 204.38,
Pb: 207.2, Bi: 208.9804, Po: 209, At: 210,
Rn: 222, Fr: 223, Ra: 226, Ac: 227,
Pa: 231.03588, Th: 232.0377, Np: 237, U: 238.02891,
Am: 243, Pu: 244, Cm: 247, Bk: 247,
Cf: 251, Es: 252, Fm: 257, Ubn: 299,
Uue: 315
}} rplc ':';'=:'; ',';'['; LF;''
 
NB. 0: punctuation, 1: numeric, 2: upper case, 3: lower case
ctyp=: e.&'0123456789' + (2*]~:tolower) + 3*]~:toupper
tokenize=: (0;(0 10#:10*do;._2{{)n
1.1 2.1 3.1 4.1 NB. start here
1.2 2.2 3.2 4.2 NB. punctuation is 1 character per word
1.2 2 3.2 4.2 NB. numeric characters are word forming
1.2 2.2 3.2 4 NB. upper case always begins a word
1.2 2.2 3.2 4 NB. lower case always continues a word
}});ctyp a.)&;:
 
molar_mass=: {{
W=.,0 NB. weight stack
M=.,1 NB. multiplier stack
digit=. (1=ctyp a.)#<"0 a.
alpha=. (2=ctyp a.)#<"0 a.
for_t.|.tokenize y do. select. {.;t
case. '(' do. W=. (M #.&(2&{.) W), 2}.W
M=. 1,2}.M
case. ')' do. W=. 0,W
M=. 1,M
case. digit do.
M=. (do;t),}.M
case. alpha do. W=. (({.W)+({.M)*do;t),}.W
M=. 1,}.M
case. do. NB. ignore irrelevant whitespace
end. end. assert. 1=#W
<.@+&0.5&.(*&1000){.W
}}
 
assert 1.008 = molar_mass('H') NB. hydrogen
assert 2.016 = molar_mass('H2') NB. hydrogen gas
assert 18.015 = molar_mass('H2O') NB. water
assert 34.014 = molar_mass('H2O2') NB. hydrogen peroxide
assert 34.014 = molar_mass('(HO)2') NB. hydrogen peroxide
assert 142.036 = molar_mass('Na2SO4') NB. sodium sulfate
assert 84.162 = molar_mass('C6H12') NB. cyclohexane
assert 186.295 = molar_mass('COOH(C(CH3)2)3CH3') NB. butyric or butanoic acid
assert 176.124 = molar_mass('C6H4O2(OH)4') NB. vitamin C
assert 386.664 = molar_mass('C27H46O') NB. cholesterol
assert 315 = molar_mass('Uue') NB. ununennium
</syntaxhighlight>
 
=={{header|Java}}==
{{trans|Kotlin}}
<syntaxhighlight lang="java">import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
 
public class ChemicalCalculator {
private static final Map<String, Double> atomicMass = new HashMap<>();
 
static {
atomicMass.put("H", 1.008);
atomicMass.put("He", 4.002602);
atomicMass.put("Li", 6.94);
atomicMass.put("Be", 9.0121831);
atomicMass.put("B", 10.81);
atomicMass.put("C", 12.011);
atomicMass.put("N", 14.007);
atomicMass.put("O", 15.999);
atomicMass.put("F", 18.998403163);
atomicMass.put("Ne", 20.1797);
atomicMass.put("Na", 22.98976928);
atomicMass.put("Mg", 24.305);
atomicMass.put("Al", 26.9815385);
atomicMass.put("Si", 28.085);
atomicMass.put("P", 30.973761998);
atomicMass.put("S", 32.06);
atomicMass.put("Cl", 35.45);
atomicMass.put("Ar", 39.948);
atomicMass.put("K", 39.0983);
atomicMass.put("Ca", 40.078);
atomicMass.put("Sc", 44.955908);
atomicMass.put("Ti", 47.867);
atomicMass.put("V", 50.9415);
atomicMass.put("Cr", 51.9961);
atomicMass.put("Mn", 54.938044);
atomicMass.put("Fe", 55.845);
atomicMass.put("Co", 58.933194);
atomicMass.put("Ni", 58.6934);
atomicMass.put("Cu", 63.546);
atomicMass.put("Zn", 65.38);
atomicMass.put("Ga", 69.723);
atomicMass.put("Ge", 72.630);
atomicMass.put("As", 74.921595);
atomicMass.put("Se", 78.971);
atomicMass.put("Br", 79.904);
atomicMass.put("Kr", 83.798);
atomicMass.put("Rb", 85.4678);
atomicMass.put("Sr", 87.62);
atomicMass.put("Y", 88.90584);
atomicMass.put("Zr", 91.224);
atomicMass.put("Nb", 92.90637);
atomicMass.put("Mo", 95.95);
atomicMass.put("Ru", 101.07);
atomicMass.put("Rh", 102.90550);
atomicMass.put("Pd", 106.42);
atomicMass.put("Ag", 107.8682);
atomicMass.put("Cd", 112.414);
atomicMass.put("In", 114.818);
atomicMass.put("Sn", 118.710);
atomicMass.put("Sb", 121.760);
atomicMass.put("Te", 127.60);
atomicMass.put("I", 126.90447);
atomicMass.put("Xe", 131.293);
atomicMass.put("Cs", 132.90545196);
atomicMass.put("Ba", 137.327);
atomicMass.put("La", 138.90547);
atomicMass.put("Ce", 140.116);
atomicMass.put("Pr", 140.90766);
atomicMass.put("Nd", 144.242);
atomicMass.put("Pm", 145.0);
atomicMass.put("Sm", 150.36);
atomicMass.put("Eu", 151.964);
atomicMass.put("Gd", 157.25);
atomicMass.put("Tb", 158.92535);
atomicMass.put("Dy", 162.500);
atomicMass.put("Ho", 164.93033);
atomicMass.put("Er", 167.259);
atomicMass.put("Tm", 168.93422);
atomicMass.put("Yb", 173.054);
atomicMass.put("Lu", 174.9668);
atomicMass.put("Hf", 178.49);
atomicMass.put("Ta", 180.94788);
atomicMass.put("W", 183.84);
atomicMass.put("Re", 186.207);
atomicMass.put("Os", 190.23);
atomicMass.put("Ir", 192.217);
atomicMass.put("Pt", 195.084);
atomicMass.put("Au", 196.966569);
atomicMass.put("Hg", 200.592);
atomicMass.put("Tl", 204.38);
atomicMass.put("Pb", 207.2);
atomicMass.put("Bi", 208.98040);
atomicMass.put("Po", 209.0);
atomicMass.put("At", 210.0);
atomicMass.put("Rn", 222.0);
atomicMass.put("Fr", 223.0);
atomicMass.put("Ra", 226.0);
atomicMass.put("Ac", 227.0);
atomicMass.put("Th", 232.0377);
atomicMass.put("Pa", 231.03588);
atomicMass.put("U", 238.02891);
atomicMass.put("Np", 237.0);
atomicMass.put("Pu", 244.0);
atomicMass.put("Am", 243.0);
atomicMass.put("Cm", 247.0);
atomicMass.put("Bk", 247.0);
atomicMass.put("Cf", 251.0);
atomicMass.put("Es", 252.0);
atomicMass.put("Fm", 257.0);
atomicMass.put("Uue", 315.0);
atomicMass.put("Ubn", 299.0);
}
 
private static double evaluate(String s) {
String sym = s + "[";
double sum = 0.0;
StringBuilder symbol = new StringBuilder();
String number = "";
for (int i = 0; i < sym.length(); ++i) {
char c = sym.charAt(i);
if ('@' <= c && c <= '[') {
// @, A-Z, [
int n = 1;
if (!number.isEmpty()) {
n = Integer.parseInt(number);
}
if (symbol.length() > 0) {
sum += atomicMass.getOrDefault(symbol.toString(), 0.0) * n;
}
if (c == '[') {
break;
}
symbol = new StringBuilder(String.valueOf(c));
number = "";
} else if ('a' <= c && c <= 'z') {
symbol.append(c);
} else if ('0' <= c && c <= '9') {
number += c;
} else {
throw new RuntimeException("Unexpected symbol " + c + " in molecule");
}
}
return sum;
}
 
private static String replaceParens(String s) {
char letter = 'a';
String si = s;
while (true) {
int start = si.indexOf('(');
if (start == -1) {
break;
}
 
for (int i = start + 1; i < si.length(); ++i) {
if (si.charAt(i) == ')') {
String expr = si.substring(start + 1, i);
String symbol = "@" + letter;
String pattern = Pattern.quote(si.substring(start, i + 1));
si = si.replaceFirst(pattern, symbol);
atomicMass.put(symbol, evaluate(expr));
letter++;
break;
}
if (si.charAt(i) == '(') {
start = i;
}
}
}
return si;
}
 
public static void main(String[] args) {
List<String> molecules = List.of(
"H", "H2", "H2O", "H2O2", "(HO)2", "Na2SO4", "C6H12",
"COOH(C(CH3)2)3CH3", "C6H4O2(OH)4", "C27H46O", "Uue"
);
for (String molecule : molecules) {
double mass = evaluate(replaceParens(molecule));
System.out.printf("%17s -> %7.3f\n", molecule, mass);
}
}
}</syntaxhighlight>
{{out}}
<pre> H -> 1.008
H2 -> 2.016
H2O -> 18.015
H2O2 -> 34.014
(HO)2 -> 34.014
Na2SO4 -> 142.036
C6H12 -> 84.162
COOH(C(CH3)2)3CH3 -> 186.295
C6H4O2(OH)4 -> 176.124
C27H46O -> 386.664
Uue -> 315.000</pre>
 
=={{header|JavaScript}}==
<syntaxhighlight lang="javascript">
const MASSES = {
C: 12.011,
H: 1.008,
Na: 22.98976928,
O: 15.99,
Sb: 121.76,
Sn: 118.71,
S: 32.06,
Uue: 315
}; // to be continued
 
function getMolarMass(formula) {
formula = formula.replace(/[0-9]+/g, x => '*' + x + ' ');
formula = formula.replace(/[A-Z][A-Z]/g, x => x[0] + '+' + x[1]);
formula = formula.replace(/[0-9] [A-Z]/g, x => x[0] + '+' + x[2]);
formula = formula.replace(/[A-Z]\(/g, x => x[0] + '+' + x[1]);
formula = formula.replace(/[0-9] \(/g, x => x[0] + '+' + x[2]);
formula = formula.replace(/[A-Z][A-Z]/g, x => x[0] + '+' + x[1]);
for (let key in MASSES)
formula = formula.replace(new RegExp(key, 'g'), MASSES[key]);
return eval(formula);
}
 
// testing
function getSubNums(str) { return str.replace(/[0-9]/g, x => '₀₁₂₃₄₅₆₇₈₉'[x]); }
 
let formulae =
'H H2 H2O H2O2 (HO)2 Na2SO4 C6H12 COOH(C(CH3)2)3CH3 C6H4O2(OH)4 C27H46O Uue'.split(' ');
 
for (let i = 0; i < formulae.length; i++)
console.log(`${getSubNums(formulae[i])}: ${getMolarMass(formulae[i]).toPrecision(3)}`);
</syntaxhighlight>
 
{{out}}
<pre>
H: 1.01
H₂: 2.02
H₂O: 18.0
H₂O₂: 34.0
(HO)₂: 34.0
Na₂SO₄: 142
C₆H₁₂: 84.2
COOH(C(CH₃)₂)₃CH₃: 186
C₆H₄O₂(OH)₄: 176
C₂₇H₄₆O: 387
Uue: 315
</pre>
=={{header|jq}}==
[[Category:PEG]]
{{works with|jq}}
'''Works with gojq, the Go implementation of jq'''
 
jq is well-suited to [[:Category:PEG|"Parsing Expression Grammars"]] (PEGs) so
this entry illustrates how to implement the chemical calculator using a PEG approach.
 
In the remainder of this entry we focus on the highlights. The complete program is on the
subpage at [[Chemical calculator/jq]].
 
To understand the PEG grammar presented below, here is a table showing
the correspondence between the main PEG operators (on the left) and jq constructs (on the right),
the first two of which (`|` and `//`)
are part of the jq language, and the others of which are defined as jq functions
on the subpage.
 
<pre>
Sequence: e1 e2 e1 | e2
Ordered choice: e1 / e2 e1 // e2
Zero-or-more: e* star(E)
One-or-more: e+ plus(E)
Optional: e? optional(E)
And-predicate: &e amp(E)
Not-predicate: !e neg(E)
</pre>
 
'''The PEG grammar'''
<syntaxhighlight lang="jq">def Element:
parse("(?<e>^[A-Z][a-z]*)"); # greedy
 
def Number: parseNumber("^[0-9]+"); # greedy
 
def EN: Element | optional(Number);
 
def Parenthesized:
consume("[(]")
| box( (plus(EN) | optional(Parenthesized)) // (Parenthesized | plus(EN)) )
| consume("[)]")
| Number;
 
def Formula:
(plus(EN) | Parenthesized | Formula)
// (plus(EN) | optional(Parenthesized))
// (Parenthesized | optional(Formula)) ;</syntaxhighlight>
'''Evaluation of the parsed expression'''
 
This is accomplished using the `eval` function defined on the subpage.
 
'''The task expressed in terms of assertions'''
<syntaxhighlight lang="text"># A "debug" statement has been retained so that the parsed chemical formula can be seen.
def molar_mass(formula):
{remainder: formula} | Formula | .result | debug | eval;
 
def assert(a; b):
if (a - b)|length > 1e-3 then "\(a) != \(b)" else empty end;
 
def task:
assert( 1.008; molar_mass("H")), # hydrogen
assert( 2.016; molar_mass("H2")), # hydrogen gas
assert( 18.015; molar_mass("H2O")), # water
assert( 34.014; molar_mass("H2O2")), # hydrogen peroxide
assert( 34.014; molar_mass("(HO)2")), # hydrogen peroxide
assert( 142.036; molar_mass("Na2SO4")), # sodium sulfate
assert( 84.162; molar_mass("C6H12")), # cyclohexane
assert( 186.295; molar_mass("COOH(C(CH3)2)3CH3")), # butyric or butanoic acid
assert( 176.124; molar_mass("C6H4O2(OH)4")), # vitamin C
assert( 386.664; molar_mass("C27H46O")), # cholesterol
assert( 315 ; molar_mass("Uue")) # ununennium
;</syntaxhighlight>
{{out}}
As mentioned above, a "debug" statement has been retained so that the parsed chemical formula can be seen.
<pre>
["DEBUG:",["H"]]
["DEBUG:",["H",2]]
["DEBUG:",["H",2,"O"]]
["DEBUG:",["H",2,"O",2]]
["DEBUG:",[["H","O"],2]]
["DEBUG:",["Na",2,"S","O",4]]
["DEBUG:",["C",6,"H",12]]
["DEBUG:",["C","O","O","H",["C",["C","H",3],2],3,"C","H",3]]
["DEBUG:",["C",6,"H",4,"O",2,["O","H"],4]]
["DEBUG:",["C",27,"H",46,"O"]]
["DEBUG:",["Uue"]]
</pre>
 
=={{header|Julia}}==
Note that Julia's 64-bit floating point gets a slightly different result for one of the assertions, hence a small change in the last example. The function uses Julia's own language parser to evaluate the compound as an arithmetic expression.
<langsyntaxhighlight lang="julia">const H = 1.008
const He = 4.002602
const Li = 6.94
Line 1,403 ⟶ 2,819:
@assert 84.162 == molar_mass("C6H12")
@assert 186.29500000000002 == molar_mass("COOH(C(CH3)2)3CH3")
</syntaxhighlight>
</lang>
No assertion errors.
 
=={{header|Kotlin}}==
{{trans|D}}
<langsyntaxhighlight lang="scala">var atomicMass = mutableMapOf(
"H" to 1.008,
"He" to 4.002602,
Line 1,582 ⟶ 2,997:
println("$moleStr -> $massStr")
}
}</langsyntaxhighlight>
{{out}}
<pre> H -> 1.008
Line 1,595 ⟶ 3,010:
C27H46O -> 386.664
Uue -> 315.000</pre>
=={{header|Lua}}==
{{trans|C#}}
<syntaxhighlight lang="lua">atomicMass = {
["H"] = 1.008,
["He"] = 4.002602,
["Li"] = 6.94,
["Be"] = 9.0121831,
["B"] = 10.81,
["C"] = 12.011,
["N"] = 14.007,
["O"] = 15.999,
["F"] = 18.998403163,
["Ne"] = 20.1797,
["Na"] = 22.98976928,
["Mg"] = 24.305,
["Al"] = 26.9815385,
["Si"] = 28.085,
["P"] = 30.973761998,
["S"] = 32.06,
["Cl"] = 35.45,
["Ar"] = 39.948,
["K"] = 39.0983,
["Ca"] = 40.078,
["Sc"] = 44.955908,
["Ti"] = 47.867,
["V"] = 50.9415,
["Cr"] = 51.9961,
["Mn"] = 54.938044,
["Fe"] = 55.845,
["Co"] = 58.933194,
["Ni"] = 58.6934,
["Cu"] = 63.546,
["Zn"] = 65.38,
["Ga"] = 69.723,
["Ge"] = 72.630,
["As"] = 74.921595,
["Se"] = 78.971,
["Br"] = 79.904,
["Kr"] = 83.798,
["Rb"] = 85.4678,
["Sr"] = 87.62,
["Y"] = 88.90584,
["Zr"] = 91.224,
["Nb"] = 92.90637,
["Mo"] = 95.95,
["Ru"] = 101.07,
["Rh"] = 102.90550,
["Pd"] = 106.42,
["Ag"] = 107.8682,
["Cd"] = 112.414,
["In"] = 114.818,
["Sn"] = 118.710,
["Sb"] = 121.760,
["Te"] = 127.60,
["I"] = 126.90447,
["Xe"] = 131.293,
["Cs"] = 132.90545196,
["Ba"] = 137.327,
["La"] = 138.90547,
["Ce"] = 140.116,
["Pr"] = 140.90766,
["Nd"] = 144.242,
["Pm"] = 145,
["Sm"] = 150.36,
["Eu"] = 151.964,
["Gd"] = 157.25,
["Tb"] = 158.92535,
["Dy"] = 162.500,
["Ho"] = 164.93033,
["Er"] = 167.259,
["Tm"] = 168.93422,
["Yb"] = 173.054,
["Lu"] = 174.9668,
["Hf"] = 178.49,
["Ta"] = 180.94788,
["W"] = 183.84,
["Re"] = 186.207,
["Os"] = 190.23,
["Ir"] = 192.217,
["Pt"] = 195.084,
["Au"] = 196.966569,
["Hg"] = 200.592,
["Tl"] = 204.38,
["Pb"] = 207.2,
["Bi"] = 208.98040,
["Po"] = 209,
["At"] = 210,
["Rn"] = 222,
["Fr"] = 223,
["Ra"] = 226,
["Ac"] = 227,
["Th"] = 232.0377,
["Pa"] = 231.03588,
["U"] = 238.02891,
["Np"] = 237,
["Pu"] = 244,
["Am"] = 243,
["Cm"] = 247,
["Bk"] = 247,
["Cf"] = 251,
["Es"] = 252,
["Fm"] = 257,
["Uue"] = 315,
["Ubn"] = 299,
}
 
function evaluate(s)
s = s .. '['
local sum = 0.0
local symbol = ""
local number = ""
 
for i=1,s:len() do
local c = s:sub(i,i)
if '@' <= c and c <= '[' then
local n = 1
if number ~= "" then
n = tonumber(number)
end
if symbol ~= "" then
sum = sum + atomicMass[symbol] * n
end
if c == '[' then
break
end
symbol = tostring(c)
number = ""
elseif 'a' <= c and c <= 'z' then
symbol = symbol .. c
elseif '0' <= c and c <= '9' then
number = number .. c
else
error("Unexpected symbol `"..c.."` in molecule")
end
end
 
return sum
end
 
function replaceFirst(text, search, replacement)
local pattern = search:gsub('%W', '%%%1')
return string.gsub(text, pattern, replacement, 1)
end
 
function replaceParens(s)
local letter = "s"
while true do
local start = string.find(s, "(", 1, true)
if start == nil then
break
end
 
for i=start,s:len() do
local c = s:sub(i,i)
if c == ')' then
local expr = s:sub(start + 1, i - 1)
local symbol = '@' .. letter
local search = s:sub(start, i)
s = replaceFirst(s, search, symbol)
atomicMass[symbol] = evaluate(expr)
letter = string.char(string.byte(letter) + 1)
break
end
if c == '(' then
start = i
end
end
end
return s
end
 
local molecules = {
"H", "H2", "H2O", "H2O2", "(HO)2", "Na2SO4", "C6H12",
"COOH(C(CH3)2)3CH3", "C6H4O2(OH)4", "C27H46O", "Uue"
}
 
for i,molecule in pairs(molecules) do
local mass = evaluate(replaceParens(molecule))
print(string.format("%17s -> %7.3f", molecule, mass))
end</syntaxhighlight>
{{out}}
<pre> H -> 1.008
H2 -> 2.016
H2O -> 18.015
H2O2 -> 34.014
(HO)2 -> 34.014
Na2SO4 -> 142.036
C6H12 -> 84.162
COOH(C(CH3)2)3CH3 -> 186.295
C6H4O2(OH)4 -> 176.124
C27H46O -> 386.664
Uue -> 315.000</pre>
=={{header|Nim}}==
* Nim lacks runtime eval, that's the reason for so much code. (And me being a sloppy programmer)
* Also, seqs can't contain mixed types.
 
<langsyntaxhighlight lang="python">#? replace(sub = "\t", by = " ")
 
import tables, strutils, sequtils, math
Line 1,711 ⟶ 3,317:
assert 176.124 == molar_mass "C6H4O2(OH)4" # Vitamin C
assert 386.664 == molar_mass "C27H46O" # Cholesterol
assert 315 == molar_mass "Uue"</langsyntaxhighlight>
 
=={{header|Perl}}==
===Grammar===
<langsyntaxhighlight lang="perl">use strict;
use warnings;
use List::Util;
Line 1,735 ⟶ 3,340:
for (<H H2 H2O Na2SO4 C6H12 COOH(C(CH3)2)3CH3>) {
printf "%7.3f %s\n", $g->weight($_), $_
}</langsyntaxhighlight>
 
===Regular Expression===
<langsyntaxhighlight lang="perl">use strict;
use warnings;
my %atomic_weight = < H 1.008 C 12.011 O 15.999 Na 22.99 S 32.06 >;
Line 1,763 ⟶ 3,368:
}
 
molar_mass($_) for <H H2 H2O Na2SO4 C6H12 COOH(C(CH3)2)3CH3></langsyntaxhighlight>
{{out}}
<pre> 1.008 H1 H
Line 1,771 ⟶ 3,376:
84.162 C6H12 C6H12
186.295 C11H22O2 COOH(C(CH3)2)3CH3</pre>
 
=={{header|Perl 6}}==
<lang perl6>my %ATOMIC_MASS =
H => 1.008 , Fe => 55.845 , Te => 127.60 , Ir => 192.217 ,
He => 4.002602 , Co => 58.933194 , I => 126.90447 , Pt => 195.084 ,
Li => 6.94 , Ni => 58.6934 , Xe => 131.293 , Au => 196.966569 ,
Be => 9.0121831 , Cu => 63.546 , Cs => 132.90545196 , Hg => 200.592 ,
B => 10.81 , Zn => 65.38 , Ba => 137.327 , Tl => 204.38 ,
C => 12.011 , Ga => 69.723 , La => 138.90547 , Pb => 207.2 ,
N => 14.007 , Ge => 72.630 , Ce => 140.116 , Bi => 208.98040 ,
O => 15.999 , As => 74.921595 , Pr => 140.90766 , Po => 209 ,
F => 18.998403163 , Se => 78.971 , Nd => 144.242 , At => 210 ,
Ne => 20.1797 , Br => 79.904 , Pm => 145 , Rn => 222 ,
Na => 22.98976928 , Kr => 83.798 , Sm => 150.36 , Fr => 223 ,
Mg => 24.305 , Rb => 85.4678 , Eu => 151.964 , Ra => 226 ,
Al => 26.9815385 , Sr => 87.62 , Gd => 157.25 , Ac => 227 ,
Si => 28.085 , Y => 88.90584 , Tb => 158.92535 , Th => 232.0377 ,
P => 30.973761998 , Zr => 91.224 , Dy => 162.500 , Pa => 231.03588 ,
S => 32.06 , Nb => 92.90637 , Ho => 164.93033 , U => 238.02891 ,
Cl => 35.45 , Mo => 95.95 , Er => 167.259 , Np => 237 ,
Ar => 39.948 , Ru => 101.07 , Tm => 168.93422 , Pu => 244 ,
K => 39.0983 , Rh => 102.90550 , Yb => 173.054 , Am => 243 ,
Ca => 40.078 , Pd => 106.42 , Lu => 174.9668 , Cm => 247 ,
Sc => 44.955908 , Ag => 107.8682 , Hf => 178.49 , Bk => 247 ,
Ti => 47.867 , Cd => 112.414 , Ta => 180.94788 , Cf => 251 ,
V => 50.9415 , In => 114.818 , W => 183.84 , Es => 252 ,
Cr => 51.9961 , Sn => 118.710 , Re => 186.207 , Fm => 257 ,
Mn => 54.938044 , Sb => 121.760 , Os => 190.23 ,
;
grammar Chemical_formula {
my @ATOMIC_SYMBOLS = %ATOMIC_MASS.keys.sort;
 
rule TOP { ^ (<lparen>|<rparen>|<element>)+ $ }
token quantity { \d+ }
token lparen { '(' }
token rparen { ')' <quantity>? }
token element { $<e>=[@ATOMIC_SYMBOLS] <quantity>? }
}
class Chemical_formula_actions {
has @stack = 0;
method TOP ($/) { $/.make: @stack }
method lparen ($/) { push @stack, 0 }
method rparen ($/) { my $m = @stack.pop;
@stack[*-1] += ($<quantity> // 1) * $m }
method element ($/) { @stack[*-1] += ($<quantity> // 1) * %ATOMIC_MASS{~$<e>} }
}
sub molar_mass ( Str $formula --> Real ) {
Chemical_formula.parse( $formula, :actions(Chemical_formula_actions.new) )
orelse die "Chemical formula not recognized: '$formula'";
return $/.made.[0];
}
say .&molar_mass.fmt('%7.3f '), $_ for <H H2 H2O Na2SO4 C6H12 COOH(C(CH3)2)3CH3>;</lang>
{{Out}}
<pre> 1.008 H
2.016 H2
18.015 H2O
142.036 Na2SO4
84.162 C6H12
186.295 COOH(C(CH3)2)3CH3</pre>
 
=={{header|Phix}}==
A simple hand-written single-pass formula parser and evaluator in one.<br>
Line 1,836 ⟶ 3,381:
Also note that initially it all worked absolutely fine with the default precision (ie "%g" instead of "%.12g"),
and that the higher precision expected value for Na2SO4 also works just fine at both printing precisions.
<!--<syntaxhighlight lang="phix">(phixonline)-->
<lang Phix>constant elements = new_dict() -- (eg "H" -> 1.008)
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span>
 
<span style="color: #008080;">constant</span> <span style="color: #000000;">elements</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">new_dict</span><span style="color: #0000FF;">()</span> <span style="color: #000080;font-style:italic;">-- (eg "H" -&gt; 1.008)</span>
function multiplier(string formula, integer fdx)
-- check for a trailing number, or return 1
<span style="color: #008080;">function</span> <span style="color: #000000;">multiplier</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">formula</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">integer</span> <span style="color: #000000;">fdx</span><span style="color: #0000FF;">)</span>
integer n = 1
<span style="color: #000080;font-style:italic;">-- check for a trailing number, or return 1</span>
if fdx<=length(formula) then
<span style="color: #004080;">integer</span> <span style="color: #000000;">n</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span>
integer ch = formula[fdx]
<span style="color: #008080;">if</span> <span style="color: #000000;">fdx</span><span style="color: #0000FF;"><=</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">formula</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span>
if ch>='1' and ch<='9' then
<span style="color: #004080;">integer</span> <span style="color: #000000;">ch</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">formula</span><span style="color: #0000FF;">[</span><span style="color: #000000;">fdx</span><span style="color: #0000FF;">]</span>
n = ch-'0'
<span style="color: #008080;">if</span> <span style="color: #000000;">ch</span><span style="color: #0000FF;">>=</span><span style="color: #008000;">'1'</span> <span style="color: #008080;">and</span> <span style="color: #000000;">ch</span><span style="color: #0000FF;"><=</span><span style="color: #008000;">'9'</span> <span style="color: #008080;">then</span>
fdx += 1
<span style="color: #000000;">n</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">ch</span><span style="color: #0000FF;">-</span><span style="color: #008000;">'0'</span>
while fdx<=length(formula) do
<span style="color: #000000;">fdx</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">1</span>
ch = formula[fdx]
<span style="color: #008080;">while</span> <span style="color: #000000;">fdx</span><span style="color: #0000FF;"><=</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">formula</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
if ch<'0' or ch>'9' then exit end if
<span style="color: #000000;">ch</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">formula</span><span style="color: #0000FF;">[</span><span style="color: #000000;">fdx</span><span style="color: #0000FF;">]</span>
n = n*10 + ch-'0'
<span style="color: #008080;">if</span> <span style="color: #000000;">ch</span><span style="color: #0000FF;"><</span><span style="color: #008000;">'0'</span> <span style="color: #008080;">or</span> <span style="color: #000000;">ch</span><span style="color: #0000FF;">></span><span style="color: #008000;">'9'</span> <span style="color: #008080;">then</span> <span style="color: #008080;">exit</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
fdx += 1
<span style="color: #000000;">n</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">n</span><span style="color: #0000FF;">*</span><span style="color: #000000;">10</span> <span style="color: #0000FF;">+</span> <span style="color: #000000;">ch</span><span style="color: #0000FF;">-</span><span style="color: #008000;">'0'</span>
end while
<span style="color: #000000;">fdx</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">1</span>
end if
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span>
end if
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
return {n,fdx}
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
end function
<span style="color: #008080;">return</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">n</span><span style="color: #0000FF;">,</span><span style="color: #000000;">fdx</span><span style="color: #0000FF;">}</span>
 
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
procedure molar_mass(string formula, name, atom expected)
sequence stack = {0} -- (for parenthesis handling)
<span style="color: #008080;">procedure</span> <span style="color: #000000;">molar_mass</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">formula</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">name</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">atom</span> <span style="color: #000000;">expected</span><span style="color: #0000FF;">)</span>
integer sdx = 1, fdx = 1, n
<span style="color: #004080;">sequence</span> <span style="color: #000000;">stack</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">0</span><span style="color: #0000FF;">}</span> <span style="color: #000080;font-style:italic;">-- (for parenthesis handling)</span>
while fdx<=length(formula) do
<span style="color: #004080;">integer</span> <span style="color: #000000;">sdx</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">fdx</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">n</span>
integer ch = formula[fdx]
<span style="color: #008080;">while</span> <span style="color: #000000;">fdx</span><span style="color: #0000FF;"><=</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">formula</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
if ch>='A' and ch<='Z' then
<span style="color: #004080;">integer</span> <span style="color: #000000;">ch</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">formula</span><span style="color: #0000FF;">[</span><span style="color: #000000;">fdx</span><span style="color: #0000FF;">]</span>
-- All elements start with capital, rest lower
<span style="color: #008080;">if</span> <span style="color: #000000;">ch</span><span style="color: #0000FF;">>=</span><span style="color: #008000;">'A'</span> <span style="color: #008080;">and</span> <span style="color: #000000;">ch</span><span style="color: #0000FF;"><=</span><span style="color: #008000;">'Z'</span> <span style="color: #008080;">then</span>
integer fend = fdx
<span style="color: #000080;font-style:italic;">-- All elements start with capital, rest lower</span>
while fend<length(formula) do
<span style="color: #004080;">integer</span> <span style="color: #000000;">fend</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">fdx</span>
ch = formula[fend+1]
<span style="color: #008080;">while</span> <span style="color: #000000;">fend</span><span style="color: #0000FF;"><</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">formula</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
if ch<'a' or ch>'z' then exit end if
<span style="color: #000000;">ch</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">formula</span><span style="color: #0000FF;">[</span><span style="color: #000000;">fend</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]</span>
fend += 1
<span style="color: #008080;">if</span> <span style="color: #000000;">ch</span><span style="color: #0000FF;"><</span><span style="color: #008000;">'a'</span> <span style="color: #008080;">or</span> <span style="color: #000000;">ch</span><span style="color: #0000FF;">></span><span style="color: #008000;">'z'</span> <span style="color: #008080;">then</span> <span style="color: #008080;">exit</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
end while
<span style="color: #000000;">fend</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">1</span>
string element = formula[fdx..fend]
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span>
atom mass = getd(element,elements)
<span style="color: #004080;">string</span> <span style="color: #000000;">element</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">formula</span><span style="color: #0000FF;">[</span><span style="color: #000000;">fdx</span><span style="color: #0000FF;">..</span><span style="color: #000000;">fend</span><span style="color: #0000FF;">]</span>
if mass=0 then ?9/0 end if -- missing?
<span style="color: #004080;">atom</span> <span style="color: #000000;">mass</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">getd</span><span style="color: #0000FF;">(</span><span style="color: #000000;">element</span><span style="color: #0000FF;">,</span><span style="color: #000000;">elements</span><span style="color: #0000FF;">)</span>
{n,fdx} = multiplier(formula,fend+1)
<span style="color: #008080;">if</span> <span style="color: #000000;">mass</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span> <span style="color: #0000FF;">?</span><span style="color: #000000;">9</span><span style="color: #0000FF;">/</span><span style="color: #000000;">0</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span> <span style="color: #000080;font-style:italic;">-- missing?</span>
stack[sdx] += n*mass
<span style="color: #0000FF;">{</span><span style="color: #000000;">n</span><span style="color: #0000FF;">,</span><span style="color: #000000;">fdx</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">multiplier</span><span style="color: #0000FF;">(</span><span style="color: #000000;">formula</span><span style="color: #0000FF;">,</span><span style="color: #000000;">fend</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">)</span>
elsif ch='(' then
<span style="color: #000000;">stack</span><span style="color: #0000FF;">[</span><span style="color: #000000;">sdx</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">n</span><span style="color: #0000FF;">*</span><span style="color: #000000;">mass</span>
sdx += 1
<span style="color: #008080;">elsif</span> <span style="color: #000000;">ch</span><span style="color: #0000FF;">=</span><span style="color: #008000;">'('</span> <span style="color: #008080;">then</span>
stack &= 0
<span style="color: #000000;">sdx</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">1</span>
fdx += 1
<span style="color: #000000;">stack</span> <span style="color: #0000FF;">&=</span> <span style="color: #000000;">0</span>
elsif ch=')' then
<span style="color: #000000;">fdx</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">1</span>
{n,fdx} = multiplier(formula,fdx+1)
<span style="color: #008080;">elsif</span> <span style="color: #000000;">ch</span><span style="color: #0000FF;">=</span><span style="color: #008000;">')'</span> <span style="color: #008080;">then</span>
sdx -= 1
<span style="color: #0000FF;">{</span><span style="color: #000000;">n</span><span style="color: #0000FF;">,</span><span style="color: #000000;">fdx</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">multiplier</span><span style="color: #0000FF;">(</span><span style="color: #000000;">formula</span><span style="color: #0000FF;">,</span><span style="color: #000000;">fdx</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">)</span>
stack[sdx] += stack[$]*n
<span style="color: #000000;">sdx</span> <span style="color: #0000FF;">-=</span> <span style="color: #000000;">1</span>
stack = stack[1..sdx]
<span style="color: #000000;">stack</span><span style="color: #0000FF;">[</span><span style="color: #000000;">sdx</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">stack</span><span style="color: #0000FF;">[$]*</span><span style="color: #000000;">n</span>
else
<span style="color: #000000;">stack</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">stack</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">..</span><span style="color: #000000;">sdx</span><span style="color: #0000FF;">]</span>
?9/0 -- unknown?
<span style="color: #008080;">else</span>
end if
<span style="color: #0000FF;">?</span><span style="color: #000000;">9</span><span style="color: #0000FF;">/</span><span style="color: #000000;">0</span> <span style="color: #000080;font-style:italic;">-- unknown?</span>
end while
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
if sdx!=1 then ?9/0 end if -- unbalanced brackets?
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span>
if name!="" then formula &= " ("&name&")" end if
<span style="color: #008080;">if</span> <span style="color: #000000;">sdx</span><span style="color: #0000FF;">!=</span><span style="color: #000000;">1</span> <span style="color: #008080;">then</span> <span style="color: #0000FF;">?</span><span style="color: #000000;">9</span><span style="color: #0000FF;">/</span><span style="color: #000000;">0</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span> <span style="color: #000080;font-style:italic;">-- unbalanced brackets?</span>
-- string res = sprintf("%g",stack[1]), -- (still fine)
<span style="color: #008080;">if</span> <span style="color: #000000;">name</span><span style="color: #0000FF;">!=</span><span style="color: #008000;">""</span> <span style="color: #008080;">then</span> <span style="color: #000000;">formula</span> <span style="color: #0000FF;">&=</span> <span style="color: #008000;">" ("</span><span style="color: #0000FF;">&</span><span style="color: #000000;">name</span><span style="color: #0000FF;">&</span><span style="color: #008000;">")"</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
-- e = sprintf("%g",expected) -- """
<span style="color: #000080;font-style:italic;">-- string res = sprintf("%.12gg",stack[1]), -- (still fine)
-- e = sprintf("%.12gg",expected) -- """</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">sprintf</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"%.12g"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">stack</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]),</span>
if res!=e then res &= " *** ERROR: expected "&e end if
<span style="color: #000000;">e</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">sprintf</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"%.12g"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">expected</span><span style="color: #0000FF;">)</span>
printf(1,"%26s = %s\n",{formula,res})
<span style="color: #008080;">if</span> <span style="color: #000000;">res</span><span style="color: #0000FF;">!=</span><span style="color: #000000;">e</span> <span style="color: #008080;">then</span> <span style="color: #000000;">res</span> <span style="color: #0000FF;">&=</span> <span style="color: #008000;">" *** ERROR: expected "</span><span style="color: #0000FF;">&</span><span style="color: #000000;">e</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
end procedure
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"%26s = %s\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">formula</span><span style="color: #0000FF;">,</span><span style="color: #000000;">res</span><span style="color: #0000FF;">})</span>
 
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
-- (following clipped for brevity, works fine with whole table from task description pasted in)
constant etext = split("""
<span style="color: #000080;font-style:italic;">-- (following clipped for brevity, works fine with whole table from task description pasted in)</span>
H,1.008
<span style="color: #008080;">constant</span> <span style="color: #000000;">etext</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">split</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"""
C,12.011
O H,151.999008
C,12.011
Na,22.98976928
S O,3215.06999
Na,22.98976928
Cl,35.45
S,32.06
Uue,315""","\n")
Cl,35.45
for i=1 to length(etext) do
Uue,315"""</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"\n"</span><span style="color: #0000FF;">)</span>
{{string element,atom mass}} = scanf(etext[i],"%s,%f")
setd(element,mass,elements)
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">etext</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
end for
<span style="color: #004080;">string</span> <span style="color: #000000;">element</span>
molar_mass("H","Hydrogen",1.008)
<span style="color: #004080;">atom</span> <span style="color: #000000;">mass</span>
molar_mass("H2","Hydrogen gas",2.016)
<span style="color: #0000FF;">{{</span><span style="color: #000000;">element</span><span style="color: #0000FF;">,</span><span style="color: #000000;">mass</span><span style="color: #0000FF;">}}</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">scanf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">etext</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">],</span><span style="color: #008000;">"%s,%f"</span><span style="color: #0000FF;">)</span>
molar_mass("H2O","Water",18.015)
<span style="color: #7060A8;">setd</span><span style="color: #0000FF;">(</span><span style="color: #000000;">element</span><span style="color: #0000FF;">,</span><span style="color: #000000;">mass</span><span style="color: #0000FF;">,</span><span style="color: #000000;">elements</span><span style="color: #0000FF;">)</span>
molar_mass("H2O2","Hydrogen peroxide",34.014)
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
molar_mass("(HO)2","Hydrogen peroxide",34.014)
<span style="color: #000000;">molar_mass</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"H"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"Hydrogen"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1.008</span><span style="color: #0000FF;">)</span>
--molar_mass("Na2SO4","Sodium sulfate",142.036) -- (fine for "%g")
<span style="color: #000000;">molar_mass</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"H2"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"Hydrogen gas"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2.016</span><span style="color: #0000FF;">)</span>
molar_mass("Na2SO4","Sodium sulfate",142.03553856) -- """
<span style="color: #000000;">molar_mass</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"H2O"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"Water"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">18.015</span><span style="color: #0000FF;">)</span>
molar_mass("C6H12","Cyclohexane",84.162)
<span style="color: #000000;">molar_mass</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"H2O2"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"Hydrogen peroxide"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">34.014</span><span style="color: #0000FF;">)</span>
molar_mass("COOH(C(CH3)2)3CH3","",186.295)
<span style="color: #000000;">molar_mass</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"(HO)2"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"Hydrogen peroxide"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">34.014</span><span style="color: #0000FF;">)</span>
molar_mass("C6H4O2(OH)4","Vitamin C",176.124)
<span style="color: #000080;font-style:italic;">--molar_mass("Na2SO4","Sodium sulfate",142.036) -- (fine for "%g")</span>
molar_mass("C27H46O","Cholesterol",386.664)
<span style="color: #000000;">molar_mass</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Na2SO4"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"Sodium sulfate"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">142.03553856</span><span style="color: #0000FF;">)</span> <span style="color: #000080;font-style:italic;">-- """</span>
molar_mass("Uue","Ununennium",315)
<span style="color: #000000;">molar_mass</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"C6H12"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"Cyclohexane"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">84.162</span><span style="color: #0000FF;">)</span>
molar_mass("UueCl","",350.45)</lang>
<span style="color: #000000;">molar_mass</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"COOH(C(CH3)2)3CH3"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">""</span><span style="color: #0000FF;">,</span><span style="color: #000000;">186.295</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">molar_mass</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"C6H4O2(OH)4"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"Vitamin C"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">176.124</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">molar_mass</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"C27H46O"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"Cholesterol"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">386.664</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">molar_mass</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Uue"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"Ununennium"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">315</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">molar_mass</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"UueCl"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">""</span><span style="color: #0000FF;">,</span><span style="color: #000000;">350.45</span><span style="color: #0000FF;">)</span>
<!--</syntaxhighlight>-->
{{out}}
<pre>
Line 1,939 ⟶ 3,490:
UueCl = 350.45
</pre>
 
=={{header|Python}}==
{{trans|Julia}}
<langsyntaxhighlight lang="python">import re
 
ATOMIC_MASS = {"H":1.008, "C":12.011, "O":15.999, "Na":22.98976928, "S":32.06, "Uue":315}
Line 1,957 ⟶ 3,507:
return print("Atomic mass {:17s} {} {:7.3f}".format(nazwa,'\t',round(eval(s),3)))
 
</syntaxhighlight>
</lang>
{{out}}
<pre>Atomic mass H 1.008
Line 1,970 ⟶ 3,520:
Atomic mass C27H46O 386.664
Atomic mass Uue 315.000</pre>
 
=={{header|Racket}}==
 
<langsyntaxhighlight lang="racket">#lang racket
 
(define table '([H 1.008]
Line 2,013 ⟶ 3,562:
(printf "~a: ~a\n"
(~a test #:align 'right #:min-width 20)
(~r (calc test) #:precision 3)))</langsyntaxhighlight>
 
{{out}}
Line 2,029 ⟶ 3,578:
Uue: 315
</pre>
=={{header|Raku}}==
(formerly Perl 6)
<syntaxhighlight lang="raku" line>my %ATOMIC_MASS =
H => 1.008 , Fe => 55.845 , Te => 127.60 , Ir => 192.217 ,
He => 4.002602 , Co => 58.933194 , I => 126.90447 , Pt => 195.084 ,
Li => 6.94 , Ni => 58.6934 , Xe => 131.293 , Au => 196.966569 ,
Be => 9.0121831 , Cu => 63.546 , Cs => 132.90545196 , Hg => 200.592 ,
B => 10.81 , Zn => 65.38 , Ba => 137.327 , Tl => 204.38 ,
C => 12.011 , Ga => 69.723 , La => 138.90547 , Pb => 207.2 ,
N => 14.007 , Ge => 72.630 , Ce => 140.116 , Bi => 208.98040 ,
O => 15.999 , As => 74.921595 , Pr => 140.90766 , Po => 209 ,
F => 18.998403163 , Se => 78.971 , Nd => 144.242 , At => 210 ,
Ne => 20.1797 , Br => 79.904 , Pm => 145 , Rn => 222 ,
Na => 22.98976928 , Kr => 83.798 , Sm => 150.36 , Fr => 223 ,
Mg => 24.305 , Rb => 85.4678 , Eu => 151.964 , Ra => 226 ,
Al => 26.9815385 , Sr => 87.62 , Gd => 157.25 , Ac => 227 ,
Si => 28.085 , Y => 88.90584 , Tb => 158.92535 , Th => 232.0377 ,
P => 30.973761998 , Zr => 91.224 , Dy => 162.500 , Pa => 231.03588 ,
S => 32.06 , Nb => 92.90637 , Ho => 164.93033 , U => 238.02891 ,
Cl => 35.45 , Mo => 95.95 , Er => 167.259 , Np => 237 ,
Ar => 39.948 , Ru => 101.07 , Tm => 168.93422 , Pu => 244 ,
K => 39.0983 , Rh => 102.90550 , Yb => 173.054 , Am => 243 ,
Ca => 40.078 , Pd => 106.42 , Lu => 174.9668 , Cm => 247 ,
Sc => 44.955908 , Ag => 107.8682 , Hf => 178.49 , Bk => 247 ,
Ti => 47.867 , Cd => 112.414 , Ta => 180.94788 , Cf => 251 ,
V => 50.9415 , In => 114.818 , W => 183.84 , Es => 252 ,
Cr => 51.9961 , Sn => 118.710 , Re => 186.207 , Fm => 257 ,
Mn => 54.938044 , Sb => 121.760 , Os => 190.23 ,
;
grammar Chemical_formula {
my @ATOMIC_SYMBOLS = %ATOMIC_MASS.keys.sort;
 
rule TOP { ^ (<lparen>|<rparen>|<element>)+ $ }
token quantity { \d+ }
token lparen { '(' }
token rparen { ')' <quantity>? }
token element { $<e>=[@ATOMIC_SYMBOLS] <quantity>? }
}
class Chemical_formula_actions {
has @stack = 0;
method TOP ($/) { $/.make: @stack }
method lparen ($/) { push @stack, 0 }
method rparen ($/) { my $m = @stack.pop;
@stack[*-1] += ($<quantity> // 1) * $m }
method element ($/) { @stack[*-1] += ($<quantity> // 1) * %ATOMIC_MASS{~$<e>} }
}
sub molar_mass ( Str $formula --> Real ) {
Chemical_formula.parse( $formula, :actions(Chemical_formula_actions.new) )
orelse die "Chemical formula not recognized: '$formula'";
return $/.made.[0];
}
say .&molar_mass.fmt('%7.3f '), $_ for <H H2 H2O Na2SO4 C6H12 COOH(C(CH3)2)3CH3>;</syntaxhighlight>
{{Out}}
<pre> 1.008 H
2.016 H2
18.015 H2O
142.036 Na2SO4
84.162 C6H12
186.295 COOH(C(CH3)2)3CH3</pre>
=={{header|REXX}}==
This REXX version has some basic error checking to catch malformed chemical formulas.
 
Some extra coding was added to format the output better and to also include a common name for the chemical formula.
Also a more precise atomic mass for the (all) known elements is used &nbsp; (for instance, '''F''').
 
Also a more precise atomic mass for the (all) known elements is used; &nbsp; for instance for &nbsp; '''F''' &nbsp; (fluorine).
 
Some of the (newer) elements added for the REXX example are:
 
mendelevium (Md), nobelium (No), lawrencium (Lr), rutherfordium (Rf), dubnium (Db),
seaborgium (Sg), bohrium (Bh), hassium (Hs), meitnerium (Mt), darmstadtium (Ds),
roentgenium (Rg), copernicium (Cn), nihoniym (Nh), flerovium (Fl), moscovium (Mc),
livermorium (Lv), tennessine (Ts), and oganesson (Og)
<langsyntaxhighlight lang="rexx">/*REXX program calculates the molar mass from a specified chemical formula. */
numeric digits 30 /*ensure enough decimal digits for mass*/
/*─────────── [↓] table of known elements (+2 more) with their atomic mass ────────────*/
Line 2,069 ⟶ 3,678:
@.Cn=285 ; @.Hs=277 ; @.No=259 ; @.Sc= 44.955912; @.Zr= 91.224
@.Ubn=299 ; @.Uue=315
parse arg $; _ = '─'
parse arg $
say center(' chemical formula {common name} ', 45) center("molar mass", 16)
if $='' | $="," then $= ' H H2 H2O H2O2 (HO)2 Na2SO4 C6H12 ' ,
say center('' " COOH(C(CH3)2)3CH3 C6H4O2(OH , 45, _)4 center('' C27H46O Uue" , 16, _)
if $='' | $="," then $= 'H{hydrogen} H2{molecular_hydrogen} H2O2{hydrogen_peroxide}',
'(HO)2{hydrogen_peroxide} H2O{water} Na2SO4{sodium_sulfate}',
'C6H12{cyclohexane} COOH(C(CH3)2)3CH3{butyric_acid}' ,
'C6H4O2(OH)4{vitamin_C} C27H46O{cholesterol} Uue{ununennium}',
'Mg3Si4O10(OH)2{talc}'
do j=1 for words($); x= word($, j) /*obtain the formula of the molecule. */
mm=parse chemCalc(x)var x x '{' -0 name /* " /*get the molar" mass " " and also " a name. */
mm= chemCalc(x) /* " " molar mass. */
name= strip(x ' 'translate(name, 'ff'x,"_")) /* " " molar mass; fix─up name. */
if mm<0 then iterate /*if function had an error, skip output*/
say right('molar mass of ' xjustify(name, 5045-2) " is " mm /*displayshow thechemical molarname massand ofits amolar chemical.mass*/
end /*j*/
exit /*stick a fork in it, we're all done. */
Line 2,114 ⟶ 3,730:
do i=1 until \datatype(q, 'W'); q= substr(z, k+i, 1)
if datatype(q, 'W') then n= n || q /*is a digit?*/
end /*i*/; return n</langsyntaxhighlight>
{{out|output|text=&nbsp; when using the default inputs:}}
<pre>
chemical formula {common name} molar mass of H is 1.00794
───────────────────────────────────────────── ────────────────
molar mass of H2 is 2.01588
H molar{hydrogen} mass of H2O is 181.0152800794
H2 {molecular hydrogen} molar mass of H2O2 is 342.0146801588
H2O2 {hydrogen peroxide} molar mass of (HO)2 is 34.01468
(HO)2 {hydrogen peroxide} molar mass of Na2SO4 is 14234.0421385601468
H2O molar mass of {water} C6H12 is 8418.1594801528
Na2SO4 molar mass of {sodium sulfate} COOH(C(CH3)2)3CH3 is 186142.2911804213856
C6H12 molar mass{cyclohexane} of C6H4O2(OH)4 is 17684.1241215948
COOH(C(CH3)2)3CH3 {butyric acid} 186.29118
molar mass of C27H46O is 386.65354
C6H4O2(OH)4 {vitamin C} molar mass of Uue is 315176.12412
C27H46O {cholesterol} 386.65354
Uue {ununennium} 315
Mg3Si4O10(OH)2 {talc} 379.26568
</pre>
=={{header|Ruby}}==
{{trans|D}}
<syntaxhighlight lang="ruby">$atomicMass = {
"H" => 1.008,
"He" => 4.002602,
"Li" => 6.94,
"Be" => 9.0121831,
"B" => 10.81,
"C" => 12.011,
"N" => 14.007,
"O" => 15.999,
"F" => 18.998403163,
"Ne" => 20.1797,
"Na" => 22.98976928,
"Mg" => 24.305,
"Al" => 26.9815385,
"Si" => 28.085,
"P" => 30.973761998,
"S" => 32.06,
"Cl" => 35.45,
"Ar" => 39.948,
"K" => 39.0983,
"Ca" => 40.078,
"Sc" => 44.955908,
"Ti" => 47.867,
"V" => 50.9415,
"Cr" => 51.9961,
"Mn" => 54.938044,
"Fe" => 55.845,
"Co" => 58.933194,
"Ni" => 58.6934,
"Cu" => 63.546,
"Zn" => 65.38,
"Ga" => 69.723,
"Ge" => 72.630,
"As" => 74.921595,
"Se" => 78.971,
"Br" => 79.904,
"Kr" => 83.798,
"Rb" => 85.4678,
"Sr" => 87.62,
"Y" => 88.90584,
"Zr" => 91.224,
"Nb" => 92.90637,
"Mo" => 95.95,
"Ru" => 101.07,
"Rh" => 102.90550,
"Pd" => 106.42,
"Ag" => 107.8682,
"Cd" => 112.414,
"In" => 114.818,
"Sn" => 118.710,
"Sb" => 121.760,
"Te" => 127.60,
"I" => 126.90447,
"Xe" => 131.293,
"Cs" => 132.90545196,
"Ba" => 137.327,
"La" => 138.90547,
"Ce" => 140.116,
"Pr" => 140.90766,
"Nd" => 144.242,
"Pm" => 145,
"Sm" => 150.36,
"Eu" => 151.964,
"Gd" => 157.25,
"Tb" => 158.92535,
"Dy" => 162.500,
"Ho" => 164.93033,
"Er" => 167.259,
"Tm" => 168.93422,
"Yb" => 173.054,
"Lu" => 174.9668,
"Hf" => 178.49,
"Ta" => 180.94788,
"W" => 183.84,
"Re" => 186.207,
"Os" => 190.23,
"Ir" => 192.217,
"Pt" => 195.084,
"Au" => 196.966569,
"Hg" => 200.592,
"Tl" => 204.38,
"Pb" => 207.2,
"Bi" => 208.98040,
"Po" => 209,
"At" => 210,
"Rn" => 222,
"Fr" => 223,
"Ra" => 226,
"Ac" => 227,
"Th" => 232.0377,
"Pa" => 231.03588,
"U" => 238.02891,
"Np" => 237,
"Pu" => 244,
"Am" => 243,
"Cm" => 247,
"Bk" => 247,
"Cf" => 251,
"Es" => 252,
"Fm" => 257,
"Uue" => 315,
"Ubn" => 299,
}
 
def evaluate(s)
s += "[" # add end of string marker
sum = 0.0
i = 0
symbol = ""
number = ""
while i < s.length
c = s[i]
if '@' <= c and c <= '[' then
n = 1
if number != "" then
n = number.to_i
end
if symbol != "" then
mass = $atomicMass[symbol]
sum = sum + mass * n
end
if c == '[' then
break
end
symbol = c.to_s
number = ""
elsif 'a' <= c and c <= 'z' then
symbol = symbol + c
elsif '0' <= c and c <= '9' then
number = number + c
else
raise "Unexpected symbol %c in molecule" % [c]
end
i = i + 1
end
return sum
end
 
def replaceParens(s)
letter = 'a'
while true
start = s.index '('
if start == nil then
break
end
 
i = start + 1
while i < s.length
if s[i] == ')' then
expr = s[start + 1 .. i - 1]
symbol = "@%c" % [letter]
r = s[start .. i + 0]
s = s.sub(r, symbol)
$atomicMass[symbol] = evaluate(expr)
letter = letter.next
break
end
if s[i] == '(' then
start = i
end
 
i = i + 1
end
end
return s
end
 
def main
molecules = [
"H", "H2", "H2O", "H2O2", "(HO)2", "Na2SO4", "C6H12",
"COOH(C(CH3)2)3CH3", "C6H4O2(OH)4", "C27H46O", "Uue"
]
for molecule in molecules
mass = evaluate(replaceParens(molecule))
print "%17s -> %7.3f\n" % [molecule, mass]
end
end
 
main()</syntaxhighlight>
{{out}}
<pre> H -> 1.008
H2 -> 2.016
H2O -> 18.015
H2O2 -> 34.014
(HO)2 -> 34.014
Na2SO4 -> 142.036
C6H12 -> 84.162
COOH(C(CH3)2)3CH3 -> 186.295
C6H4O2(OH)4 -> 176.124
C27H46O -> 386.664
Uue -> 315.000</pre>
 
=={{header|Rust}}==
Rust is precompiled for execution, so there is no runtime eval for arbitrary Rust code. The `eval` crate allows Rust to process syntax similar to JSON while executing.
This allows the example to run an `eval` on strings which have been first translated into numeric arithmetic.
<syntaxhighlight lang="rust">use regex::Regex;
use eval::{eval, to_value};
use aho_corasick::AhoCorasick;
 
const ELEMENTS: &[&str; 5] = &["H", "C", "O", "Na", "S",];
const WEIGHTS: &[&str; 5] = &["1.008", "12.011", "15.999", "22.98976928", "32.06",];
 
fn main() {
let test_strings = ["H", "H2", "H2O", "Na2SO4", "C6H12", "COOH(C(CH3)2)3CH3"];
let test_values = [1.008, 2.016, 18.015, 142.03553856000002, 84.162, 186.29500000000002];
let ac = AhoCorasick::new(ELEMENTS).unwrap();
let regex1 = Regex::new(r"(?<num>\d+)").unwrap();
let regex2 = Regex::new(r"(?<group>[A-Z][a-z]{0,2}|\()").unwrap();
 
for (i, s) in test_strings.iter().enumerate() {
let s1 = regex1.replace_all(*s, "*$num");
let s2 = regex2.replace_all(&s1, "+$group");
let s3 = ac.replace_all(&s2, WEIGHTS).trim_start_matches("+").replace("(+", "(");
let mass: Result<eval::Value, eval::Error> = eval(&s3);
assert_eq!(mass, Ok(to_value(test_values[i])));
println!("The molar mass of {} checks correctly as {}.", s, test_values[i]);
}
}
</syntaxhighlight>{{out}}
<pre>
The molar mass of H checks correctly as 1.008.
The molar mass of H2 checks correctly as 2.016.
The molar mass of H2O checks correctly as 18.015.
The molar mass of Na2SO4 checks correctly as 142.03553856000002.
The molar mass of C6H12 checks correctly as 84.162.
The molar mass of COOH(C(CH3)2)3CH3 checks correctly as 186.29500000000002.
</pre>
 
=={{header|Swift}}==
 
<syntaxhighlight lang="swift">import Foundation
 
struct Chem {
struct Molecule {
var formula: String
var parts: [Molecule]
var quantity = 1
 
var molarMass: Double {
switch parts.count {
case 0:
return Chem.atomicWeights[formula]! * Double(quantity)
case _:
return parts.lazy.map({ $0.molarMass }).reduce(0, +) * Double(quantity)
}
}
 
private init(formula: String, parts: [Molecule], quantity: Int) {
self.formula = formula
self.parts = parts
self.quantity = quantity
}
 
init?(fromString str: String) {
guard let mol = Molecule.parseString(str[...]) else {
return nil
}
 
self = mol
}
 
private static func parseString(_ str: Substring) -> Molecule? {
guard !str.isEmpty else {
return nil
}
 
var parts = [Molecule]()
var workingMol = ""
var idx = str.startIndex
 
func completeAtom() -> Bool {
guard Chem.atomicWeights.keys.contains(workingMol) else {
return false
}
 
parts.append(Molecule(formula: workingMol, parts: [], quantity: 1))
workingMol = ""
 
return true
}
 
while idx != str.endIndex {
let char = str[idx]
 
guard char.isASCII else {
return nil
}
 
if (char.isUppercase || char == "(" || char.isNumber) && !workingMol.isEmpty {
guard completeAtom() else {
return nil
}
}
 
if char == "(" {
var parenLevel = 1
 
let subMolStart = str.index(after: idx)
idx = subMolStart
 
while parenLevel != 0 {
guard idx != str.endIndex else {
return nil
}
 
if str[idx] == "(" {
parenLevel += 1
} else if str[idx] == ")" {
parenLevel -= 1
}
 
if parenLevel != 0 {
idx = str.index(after: idx)
}
}
 
guard let subMol = parseString(str[subMolStart..<idx]) else {
return nil
}
 
parts.append(subMol)
 
idx = str.index(after: idx)
 
continue
} else if char == ")" {
fatalError()
}
 
workingMol.append(char)
 
if char.isNumber {
guard !parts.isEmpty else {
return nil
}
 
var workNum = workingMol
 
idx = str.index(after: idx)
 
while idx != str.endIndex && str[idx].isNumber {
workNum.append(str[idx])
idx = str.index(after: idx)
}
 
parts[parts.count - 1].quantity = Int(workNum)!
workingMol = ""
 
continue
}
 
idx = str.index(after: idx)
}
 
guard workingMol.isEmpty || completeAtom() else {
return nil
}
 
return Molecule(formula: String(str), parts: parts, quantity: 1)
}
}
 
static func calculateMolarMass(of chem: String) -> Double? {
guard let mol = Molecule(fromString: chem) else {
return nil
}
 
return mol.molarMass
}
 
fileprivate static let atomicWeights = [
"H": 1.008,
"He": 4.002602,
"Li": 6.94,
"Be": 9.0121831,
"B": 10.81,
"C": 12.011,
"N": 14.007,
"O": 15.999,
"F": 18.998403163,
"Ne": 20.1797,
"Na": 22.98976928,
"Mg": 24.305,
"Al": 26.9815385,
"Si": 28.085,
"P": 30.973761998,
"S": 32.06,
"Cl": 35.45,
"K": 39.0983,
"Ar": 39.948,
"Ca": 40.078,
"Sc": 44.955908,
"Ti": 47.867,
"V": 50.9415,
"Cr": 51.9961,
"Mn": 54.938044,
"Fe": 55.845,
"Ni": 58.6934,
"Co": 58.933194,
"Cu": 63.546,
"Zn": 65.38,
"Ga": 69.723,
"Ge": 72.63,
"As": 74.921595,
"Se": 78.971,
"Br": 79.904,
"Kr": 83.798,
"Rb": 85.4678,
"Sr": 87.62,
"Y": 88.90584,
"Zr": 91.224,
"Nb": 92.90637,
"Mo": 95.95,
"Ru": 101.07,
"Rh": 102.9055,
"Pd": 106.42,
"Ag": 107.8682,
"Cd": 112.414,
"In": 114.818,
"Sn": 118.71,
"Sb": 121.76,
"I": 126.90447,
"Te": 127.6,
"Xe": 131.293,
"Cs": 132.90545196,
"Ba": 137.327,
"La": 138.90547,
"Ce": 140.116,
"Pr": 140.90766,
"Nd": 144.242,
"Pm": 145,
"Sm": 150.36,
"Eu": 151.964,
"Gd": 157.25,
"Tb": 158.92535,
"Dy": 162.5,
"Ho": 164.93033,
"Er": 167.259,
"Tm": 168.93422,
"Yb": 173.054,
"Lu": 174.9668,
"Hf": 178.49,
"Ta": 180.94788,
"W": 183.84,
"Re": 186.207,
"Os": 190.23,
"Ir": 192.217,
"Pt": 195.084,
"Au": 196.966569,
"Hg": 200.592,
"Tl": 204.38,
"Pb": 207.2,
"Bi": 208.9804,
"Po": 209,
"At": 210,
"Rn": 222,
"Fr": 223,
"Ra": 226,
"Ac": 227,
"Pa": 231.03588,
"Th": 232.0377,
"Np": 237,
"U": 238.02891,
"Am": 243,
"Pu": 244,
"Cm": 247,
"Bk": 247,
"Cf": 251,
"Es": 252,
"Fm": 257,
"Ubn": 299,
"Uue": 315
]
}
 
let testCases = [
("H", "1.008"),
("H2", "2.016"),
("H2O", "18.015"),
("H2O2", "34.014"),
("(HO)2", "34.014"),
("Na2SO4", "142.036"),
("C6H12", "84.162"),
("COOH(C(CH3)2)3CH3", "186.295"),
("C6H4O2(OH)4", "176.124"),
("C27H46O", "386.664"),
("Uue", "315.000")
]
 
let fmt = { String(format: "%.3f", $0) }
 
for (mol, expected) in testCases {
guard let mass = Chem.calculateMolarMass(of: mol) else {
fatalError("Bad formula \(mol)")
}
 
assert(fmt(mass) == expected, "Incorrect result")
 
print("\(mol) => \(fmt(mass))")
}</syntaxhighlight>
 
{{out}}
 
<pre>H => 1.008
H2 => 2.016
H2O => 18.015
H2O2 => 34.014
(HO)2 => 34.014
Na2SO4 => 142.036
C6H12 => 84.162
COOH(C(CH3)2)3CH3 => 186.295
C6H4O2(OH)4 => 176.124
C27H46O => 386.664
Uue => 315.000</pre>
=={{header|VBA}}==
<syntaxhighlight lang="vba">Option Explicit
 
Enum ParsingStateCode
NORM
GROUP_JUST_ENDED
End Enum
Dim masses As Collection
 
Sub main()
Dim molecule
For Each molecule In Array("H", "H2", "H2O", "H2O2", "(HO)2", "Na2SO4", "C6H12", "COOH(C(CH3)2)3CH3", _
"C6H4O2(OH)4", "C27H46O", "Uue")
Debug.Print molecule; Tab(20); GetMM(molecule)
Next
End Sub
 
Function GetMM(ByVal f As String) As Double
If masses Is Nothing Then init
f = f & "@"
Dim pos As Long
Dim mass(5) As Double
For pos = 1 To Len(f)
Dim sym$: sym = Mid(f, pos, 1)
Select Case sym
Case "A" To "Z"
GoSub calc
Dim atom$: atom = sym
Case "a" To "z"
atom = atom & sym
Case "("
GoSub calc
Dim depth As Long: depth = depth + 1
Case ")"
GoSub calc
Dim parsingState As ParsingStateCode
parsingState = GROUP_JUST_ENDED
Case 0 To 9
Dim nStr As String
nStr = nStr & sym
Case "@"
GoSub calc
End Select
Next
GetMM = mass(0)
Exit Function
'-------------------------------------------------------------------
calc:
Dim n As Long
If nStr = "" Then
n = 1
Else
n = CLng(nStr)
End If
Select Case parsingState
Case NORM
mass(depth) = mass(depth) + masses(atom) * n
atom = ""
Case GROUP_JUST_ENDED
mass(depth) = mass(depth) * n
depth = depth - 1
mass(depth) = mass(depth) + mass(depth + 1)
parsingState = NORM
End Select
'n = 0
nStr = ""
Return
End Function
 
Sub init()
Set masses = New Collection
masses.Add 0, ""
masses.Add 1.008, "H"
masses.Add 4.002602, "He"
masses.Add 6.94, "Li"
masses.Add 9.0121831, "Be"
masses.Add 10.81, "B"
masses.Add 12.011, "C"
masses.Add 14.007, "N"
masses.Add 15.999, "O"
masses.Add 18.998403163, "F"
masses.Add 20.1797, "Ne"
masses.Add 22.98976928, "Na"
masses.Add 24.305, "Mg"
masses.Add 26.9815385, "Al"
masses.Add 28.085, "Si"
masses.Add 30.973761998, "P"
masses.Add 32.06, "S"
masses.Add 35.45, "Cl"
masses.Add 39.0983, "K"
masses.Add 39.948, "Ar"
masses.Add 40.078, "Ca"
masses.Add 44.955908, "Sc"
masses.Add 47.867, "Ti"
masses.Add 50.9415, "V"
masses.Add 51.9961, "Cr"
masses.Add 54.938044, "Mn"
masses.Add 55.845, "Fe"
masses.Add 58.6934, "Ni"
masses.Add 58.933194, "Co"
masses.Add 63.546, "Cu"
masses.Add 65.38, "Zn"
masses.Add 69.723, "Ga"
masses.Add 72.63, "Ge"
masses.Add 74.921595, "As"
masses.Add 78.971, "Se"
masses.Add 79.904, "Br"
masses.Add 83.798, "Kr"
masses.Add 85.4678, "Rb"
masses.Add 87.62, "Sr"
masses.Add 88.90584, "Y"
masses.Add 91.224, "Zr"
masses.Add 92.90637, "Nb"
masses.Add 95.95, "Mo"
masses.Add 101.07, "Ru"
masses.Add 102.9055, "Rh"
masses.Add 106.42, "Pd"
masses.Add 107.8682, "Ag"
masses.Add 112.414, "Cd"
masses.Add 114.818, "In"
masses.Add 118.71, "Sn"
masses.Add 121.76, "Sb"
masses.Add 126.90447, "I"
masses.Add 127.6, "Te"
masses.Add 131.293, "Xe"
masses.Add 132.90545196, "Cs"
masses.Add 137.327, "Ba"
masses.Add 138.90547, "La"
masses.Add 140.116, "Ce"
masses.Add 140.90766, "Pr"
masses.Add 144.242, "Nd"
masses.Add 145, "Pm"
masses.Add 150.36, "Sm"
masses.Add 151.964, "Eu"
masses.Add 157.25, "Gd"
masses.Add 158.92535, "Tb"
masses.Add 162.5, "Dy"
masses.Add 164.93033, "Ho"
masses.Add 167.259, "Er"
masses.Add 168.93422, "Tm"
masses.Add 173.054, "Yb"
masses.Add 174.9668, "Lu"
masses.Add 178.49, "Hf"
masses.Add 180.94788, "Ta"
masses.Add 183.84, "W"
masses.Add 186.207, "Re"
masses.Add 190.23, "Os"
masses.Add 192.217, "Ir"
masses.Add 195.084, "Pt"
masses.Add 196.966569, "Au"
masses.Add 200.592, "Hg"
masses.Add 204.38, "Tl"
masses.Add 207.2, "Pb"
masses.Add 208.9804, "Bi"
masses.Add 209, "Po"
masses.Add 210, "At"
masses.Add 222, "Rn"
masses.Add 223, "Fr"
masses.Add 226, "Ra"
masses.Add 227, "Ac"
masses.Add 231.03588, "Pa"
masses.Add 232.0377, "Th"
masses.Add 237, "Np"
masses.Add 238.02891, "U"
masses.Add 243, "Am"
masses.Add 244, "Pu"
masses.Add 247, "Cm"
masses.Add 247, "Bk"
masses.Add 251, "Cf"
masses.Add 252, "Es"
masses.Add 257, "Fm"
masses.Add 299, "Ubn"
masses.Add 315, "Uue"
End Sub</syntaxhighlight>
 
{{out}}
<pre>H 1,008
H2 2,016
H2O 18,015
H2O2 34,014
(HO)2 34,014
Na2SO4 142,03553856
C6H12 84,162
COOH(C(CH3)2)3CH3 186,295
C6H4O2(OH)4 176,124
C27H46O 386,664
Uue 315</pre>
=={{header|Visual Basic .NET}}==
{{trans|C#}}
<langsyntaxhighlight lang="vbnet">Module Module1
 
Dim atomicMass As New Dictionary(Of String, Double) From {
Line 2,316 ⟶ 4,638:
End Sub
 
End Module</langsyntaxhighlight>
{{out}}
<pre> H -> 1.008
Line 2,329 ⟶ 4,651:
C27H46O -> 386.664
Uue -> 315.000</pre>
=={{header|Wren}}==
{{trans|Go}}
{{libheader|Wren-fmt}}
{{libheader|Wren-str}}
<syntaxhighlight lang="wren">import "./fmt" for Fmt
import "./str" for Char, Str
 
var atomicMass = {
"H": 1.008,
"He": 4.002602,
"Li": 6.94,
"Be": 9.0121831,
"B": 10.81,
"C": 12.011,
"N": 14.007,
"O": 15.999,
"F": 18.998403163,
"Ne": 20.1797,
"Na": 22.98976928,
"Mg": 24.305,
"Al": 26.9815385,
"Si": 28.085,
"P": 30.973761998,
"S": 32.06,
"Cl": 35.45,
"Ar": 39.948,
"K": 39.0983,
"Ca": 40.078,
"Sc": 44.955908,
"Ti": 47.867,
"V": 50.9415,
"Cr": 51.9961,
"Mn": 54.938044,
"Fe": 55.845,
"Co": 58.933194,
"Ni": 58.6934,
"Cu": 63.546,
"Zn": 65.38,
"Ga": 69.723,
"Ge": 72.630,
"As": 74.921595,
"Se": 78.971,
"Br": 79.904,
"Kr": 83.798,
"Rb": 85.4678,
"Sr": 87.62,
"Y": 88.90584,
"Zr": 91.224,
"Nb": 92.90637,
"Mo": 95.95,
"Ru": 101.07,
"Rh": 102.90550,
"Pd": 106.42,
"Ag": 107.8682,
"Cd": 112.414,
"In": 114.818,
"Sn": 118.710,
"Sb": 121.760,
"Te": 127.60,
"I": 126.90447,
"Xe": 131.293,
"Cs": 132.90545196,
"Ba": 137.327,
"La": 138.90547,
"Ce": 140.116,
"Pr": 140.90766,
"Nd": 144.242,
"Pm": 145,
"Sm": 150.36,
"Eu": 151.964,
"Gd": 157.25,
"Tb": 158.92535,
"Dy": 162.500,
"Ho": 164.93033,
"Er": 167.259,
"Tm": 168.93422,
"Yb": 173.054,
"Lu": 174.9668,
"Hf": 178.49,
"Ta": 180.94788,
"W": 183.84,
"Re": 186.207,
"Os": 190.23,
"Ir": 192.217,
"Pt": 195.084,
"Au": 196.966569,
"Hg": 200.592,
"Tl": 204.38,
"Pb": 207.2,
"Bi": 208.98040,
"Po": 209,
"At": 210,
"Rn": 222,
"Fr": 223,
"Ra": 226,
"Ac": 227,
"Th": 232.0377,
"Pa": 231.03588,
"U": 238.02891,
"Np": 237,
"Pu": 244,
"Am": 243,
"Cm": 247,
"Bk": 247,
"Cf": 251,
"Es": 252,
"Fm": 257,
"Uue": 315,
"Ubn": 299
}
 
var evaluate = Fn.new { |s|
s = s + "[" // add end of string marker
var symbol = ""
var number = ""
var sum = 0
for (i in 0...s.count) {
var c = s[i]
if (Str.ge(c, "@") && Str.le(c, "[")) { // @, A-Z, [
var n = 1
if (number != "") n = Num.fromString(number)
if (symbol != "") sum = sum + atomicMass[symbol] * n
if (c == "[") break
symbol = c
number = ""
} else if (Char.isLower(c)) {
symbol = symbol + c
} else if (Char.isDigit(c)) {
number = number + c
} else {
Fiber.abort("Unexpected symbol '%(c)' in molecule.")
}
}
return sum
}
 
var replaceFirst = Fn.new { |s, from, to|
var ix = s.indexOf(from)
if (ix == -1) return s
var tail = (s.count >= ix + from.count) ? s[(ix + from.count)..-1] : ""
return s[0...ix] + to + tail
}
 
var replaceParens = Fn.new { |s|
var letter = "a"
while (true) {
var start = s.indexOf("(")
if (start == -1) return s
var restart = true
while (restart) {
var i = start + 1
while (i < s.count) {
if (s[i] == ")") {
var expr = s[start+1...i]
var symbol = "@%(letter)"
s = replaceFirst.call(s, s[start..i], symbol)
atomicMass[symbol] = evaluate.call(expr)
letter = String.fromByte(letter.bytes[0] + 1)
restart = false
break
}
if (s[i] == "(") {
start = i
break
}
i = i + 1
}
}
}
return s
}
 
var molecules = [
"H", "H2", "H2O", "H2O2", "(HO)2", "Na2SO4", "C6H12", "COOH(C(CH3)2)3CH3",
"C6H4O2(OH)4", "C27H46O", "Uue"
]
for (molecule in molecules) {
var mass = evaluate.call(replaceParens.call(molecule))
Fmt.print("$17s -> $7.3f", molecule, mass)
}</syntaxhighlight>
 
{{out}}
<pre>
H -> 1.008
H2 -> 2.016
H2O -> 18.015
H2O2 -> 34.014
(HO)2 -> 34.014
Na2SO4 -> 142.036
C6H12 -> 84.162
COOH(C(CH3)2)3CH3 -> 186.295
C6H4O2(OH)4 -> 176.124
C27H46O -> 386.664
Uue -> 315.000
</pre>
 
=={{header|zkl}}==
Really bad error checking
<langsyntaxhighlight lang="zkl">fcn molarMass(str,mass=0.0){
while(span:=str.span("(",")",False)){ // get inner most () group
group:=str[span.xplode()]; // (CH3)
Line 2,351 ⟶ 4,868:
}
ms.reduce('+);
}</langsyntaxhighlight>
<langsyntaxhighlight lang="zkl">var [const] atomicMass = Dictionary(
"Ac",227.000000, "Ag",107.868200, "Al", 26.981538, "Am",243.000000, "Ar", 39.948000,
"As", 74.921595, "At",210.000000, "Au",196.966569, "B" , 10.810000, "Ba",137.327000,
Line 2,380 ⟶ 4,897:
.concat("|","(",")([1-9]*)") )
: RegExp(_);
}();</langsyntaxhighlight>
<langsyntaxhighlight lang="zkl">foreach cstr in (T("H","H2","H2O","Na2SO4","C6H12","COOH(C(CH3)2)3CH3"))
{ println(cstr," --> ",molarMass(cstr)) }</langsyntaxhighlight>
{{out}}
Weight of H = 1.008.
Weight of H2 = 2.016.
Weight of H2O = 18.015.
Weight of H2O2 = 34.014.
Weight of (HO)2 = 34.014.
Weight of Na2SO4 = 142.036.
Weight of C6H12 = 84.162.
Weight of COOH(C(CH3)2)3CH3 = 186.295.
Weight of C6H4O2(OH)4 = 176.124.
Weight of C27H46O = 386.664.
Weight of Uue = 315.000.
<pre>
H --> 1.008
Line 2,392 ⟶ 4,920:
COOH(C(CH3)2)3CH3 --> 186.295
</pre>
=={{header|X-script}}==
<syntaxhighlight lang="zkl">
 
<var $weighttab[],
-H:1.008|He:4.002602|Li:6.94|Be:9.0121831|B:10.81|C:12.011|N:14.007|O:15.999|F:18.998403163|
-Ne:20.1797|Na:22.98976928|Mg:24.305|Al:26.9815385|Si:28.085|P:30.973761998|S:32.06|Cl:35.45|
-K:39.0983|Ar:39.948|Ca:40.078|Sc:44.955908|Ti:47.867|V:50.9415|Cr:51.9961|Mn:54.938044|
-Fe:55.845|Ni:58.6934|Co:58.933194|Cu:63.546|Zn:65.38|Ga:69.723|Ge:72.63|As:74.921595|Se:78.971|
-Br:79.904|Kr:83.798|Rb:85.4678|Sr:87.62|Y:88.90584|Zr:91.224|Nb:92.90637|Mo:95.95|Ru:101.07|
-Rh:102.9055|Pd:106.42|Ag:107.8682|Cd:112.414|In:114.818|Sn:118.71|Sb:121.76|I:126.90447|Te:127.6|
-Xe:131.293|Cs:132.90545196|Ba:137.327|La:138.90547|Ce:140.116|Pr:140.90766|Nd:144.242|Pm:145|
-Sm:150.36|Eu:151.964|Gd:157.25|Tb:158.92535|Dy:162.5|Ho:164.93033|Er:167.259|Tm:168.93422|
-Yb:173.054|Lu:174.9668|Hf:178.49|Ta:180.94788|W:183.84|Re:186.207|Os:190.23|Ir:192.217|Pt:195.084|
-Au:196.966569|Hg:200.592|Tl:204.38|Pb:207.2|Bi:208.9804|Po:209|At:210|Rn:222|Fr:223|Ra:226|Ac:227|
-Pa:231.03588|Th:232.0377|Np:237|U:238.02891|Am:243|Pu:244|Cm:247|Bk:247|Cf:251|Es:252|Fm:257|
-Ubn:299|Uue:315
->
<var $level>
<var $stackTab[]>
 
chemicalCalculator.x
--------------------
 
<def charcode,<htod <stoh $1>>>
<var $name>
<var $multiplier>
<var $unusedCharacters>
 
!"<in <sp 1>,string>
-<set $level,0>
-<set $stackTab[0],0>
-"!
 
(* 1-3 characters in a row plus optional multipier. Examples: "Uee", "NaO", "COO", "Na2" *)
?"<format l><opt <format l>><opt <format l>><opt <integer>>"?
!"
-<set $name,<p 1>>
-<set $multiplier,1>
-<set $unusedCharacters,>
-<ifis <p 2>,
--<if <charcode <p 2>>'>=96,
---(* Lower case char - add to name. *)
---<append $name,<p 2>>
---<ifis <p 3>,
----<if <charcode <p 3>>'>=96,
-----(* Lower case char again - add to name. *)
-----<append $name,<p 3>>
-----,{else}
-----(* Not for this name, put in unread buffer. *)
-----<append $unusedCharacters,<p 3>>
----->
---->
---,{else}
---(* Not for this name, put in unread buffer. *)
---<append $unusedCharacters,<p 2>>
---<append $unusedCharacters,<p 3>>
--->
-->
-(* Multiplier. *)
-<set $multiplier,1>
-<ifis <p 4>,
--<ifis $unusedCharacters,
---(* Multiplier is not for this name, put in unread buffer. *)
---<append $unusedCharacters,<p 4>>
---,{else}
---(* Use as multiplier. *)
---<set $multiplier,<p 4>>
--->
-->
-
-(* Unread unused characters. *)
-<unread $unusedCharacters>
-
-(* Update weight. *)
-<update $stackTab[$level],+$weightTab[$name]*$multiplier,3>
-"!
 
(* Beginning of group. *)
?"("?
!"
-<update $level,+1>
-<set $stackTab[$level],0>
-"!
 
(* End of group. *)
?")<opt <integer>>"?
!"
-<ifis <p 1>,
--<update $stackTab[$level],*<p 1>,3>
-->
-<update $stackTab[<calc $level-1>],+$stackTab[$level],3>
-<update $level,-1>
-"!
 
?"<eof>"?
!"
-<wcons Weight of <sp 1> = $stackTab[$level].>
-<r>
-"!
 
!"<r $stackTab[$level]>"!
--------------
 
<function assert,
-<unless $1=<c chemicalCalculator,$2>,<wcons <c chemicalCalculator,$2>!= $1.>>
->
 
<assert 1.008,H>
<assert 2.016,H2>
<assert 18.015,H2O>
<assert 34.014,H2O2>
<assert 34.014,(HO)2>
<assert 142.036,Na2SO4>
<assert 84.162,C6H12>
<assert 186.295,COOH(C(CH3)2)3CH3>
<assert 176.124,C6H4O2(OH)4>
<assert 386.664,C27H46O>
<assert 315 ,Uue>
</syntaxhighlight>
 
{{out}}
Weight of H = 1.008.<br>
Weight of H2 = 2.016.<br>
Weight of H2O = 18.015.<br>
Weight of H2O2 = 34.014.<br>
Weight of (HO)2 = 34.014.<br>
Weight of Na2SO4 = 142.036.<br>
Weight of C6H12 = 84.162.<br>
Weight of COOH(C(CH3)2)3CH3 = 186.295.<br>
Weight of C6H4O2(OH)4 = 176.124.<br>
Weight of C27H46O = 386.664.<br>
Weight of Uue = 315.000.
9,476

edits