http://www.perlmonks.org?node_id=1004991

R3volution has asked for the wisdom of the Perl Monks concerning the following question:

Hi, I am very new to perl and am having issues with a program that will allow me to calculate Chemical Formulas. I am trying to create a sub-routine to do this. So far, I have:

#!/usr/bin/perl while ($lines = <>) { chomp ($lines); (undef, $symbols, $weights) = split /,/, $lines; $weights{$key} = $weights; } print "Please enter a Chemical Formula: "; chomp ($formula = <>); @array = $formula =~ /[A-Z][a-z]?|\d+/g; sub mol_form { }

This code works as far as splitting a Formula. But I am trying to use a subroutine so that the script will properly calculate the formula. I have tried several different ways and nothing seems to work. Basically for example, If I have H2O, it will multiple the molecular weight of Hydrogen by 2 and then add that to the molecular weight Oxygen. I'm thinking I may need 2 sets of IF statements in my subroutine to get the calculation right. Of course, if there are no numbers, it will just add the molecular weights themselves. It's probablty really easy to do and I am looking too much into it. Any help would be appreciated.

Replies are listed 'Best First'.
Re: Assistance please
by Kenosis (Priest) on Nov 21, 2012 at 20:57 UTC

    Hi, R3volution, and welcome to PerlMonks!

    Perhaps the Module Chemistry::MolecularMass would be helpful to you. The following example, but using H2O, was adapted from the Module's site:

    use strict; use warnings; use Chemistry::MolecularMass; my $chemical = 'H2O'; my $mm = new Chemistry::MolecularMass; my $mass = $mm->calc_mass($chemical); if ( defined $mass ) { print "The mass of $chemical is: $mass"; } else { print "Unable to calculate the mass of $chemical"; }

    Output:

    The mass of H2O is: 18.01528
Re: Assistance please
by grondilu (Friar) on Nov 21, 2012 at 21:46 UTC

    Here is how I'd do it (I skip the part when you parse the weight table and prompt the user):

    #!/usr/bin/perl use strict; use warnings; # whatever you need to fill %weights ... sub mol_form { my $formula = shift; my $mass; for ($formula =~ /[A-Za-z]\d*/g) { /(?<element>[A-Za-z])(?<amount>\d+)?/; $mass += ($+{amount} // 1) * $weights{$+{element}}; } return $mass; } say mol_form "H2O";

    The most tricky part is to separate each group of element+optionalquantity, and then to process them. That's why I ended up with two regexes, not just one.

Re: Assistance please
by Don Coyote (Hermit) on Nov 21, 2012 at 22:07 UTC

    As for your code, the best place to start is by adding a couple of pragmas to your script. Please you ask and if I please to tell you these? Would it be so much to ask the names? or would it be a farce to tell? of what these pragmas are and when or where they may dwell? Why for a beginner the best place to begin is the start of the script with a couple of the most delightful pragmas known to exist. Their names? Their names? oh yes! my dear friend. Now, remember to put them at the beginning and not at the end. They're both written with u's and by you and if you don't use them someone will sue! So dont hesitate and stop your yawning the first of the pragmas is use warnings! did you get that? did you write that in your script? There's no time to waste here, now type use strict! There by golly and close by gosh we got this programme under the cosh!

    #! /usr/bin/perl use strict; use warnings;

    Right, so I think you may have to reconsider how your hash is constructed. The plural I would use in your script would be for the hash name. This is because the hash holds all the keys. Each of the keys is a singular key. And likewise each weight is associated to a key. So to tweak your hash a little, try something like

    #! /usr/bin/perl use strict; use warnings; my %Elements; my $line = 'a,H,5'; my (undef, $symbol, $weight) = split /,/, $line; $Elements{$symbol} = $weight; my $requestelement = $Elements{'H'}; my $symbolweight = $Elements{$symbol}; print $requestelement,' ',$symbolweight; ---------- 5 5

    You may now find accessing the hash values clearer. Make use of the strict and warnings messages to debug, its hard at first as the messages dont make a lot of sense but after a while you know what you have done. They do really help.