|
setup diary | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
def fmlwt(fml)
awt=Hash[*IO.read("formula.dat").strip.split(/\s+/m)]
r=0
fml.scan(/([A-Z][a-z]?)([\d\.]*)/){|a,n|
n=1 if n==""
r+=awt[a].to_f*n.to_f
}
r
end
のような感じで書ける。この原子量の代わりに、括弧の中の化学式に関しては自分を再帰的に呼び出すことによって、
def fmlwt(fml)
awt=Hash[*IO.read("formula.dat").strip.split(/\s+/m)]
r=0
fml.scan(/(\(.*?\)|[A-Z][a-z]?)([\d\.]*)/){|a,n|
n=1 if n==""
a=a.sub(/^\(/){""}.sub(/\)$/){""}
r+=((a=~/^[A-Z][a-z]?$/)?awt[a].to_f : fmlwt(a))*n.to_f
}
r
end
と書くと、特定の括弧の付け方に対応できるようになる。Cu(NO3)2(H2O)2.5などはうまく判定できる。しかし、(Cu(NH3)4)Cl2はうまくいかない。scanの部分の正規表現の.*?の?を取ればこれに対応するが、今度は前者に対応できなくなる。この両者をシンプルに判定するにはどうしたら良いのだろう。
def fmlwt(fml)
awt=Hash[*IO.read("formula.dat").strip.split(/\s+/m)]
fml=fml.sub(/[\(\[]([^\(\)\[\]]*)[\)\]]([\d\.]*)/){
n=($2=="")?1:$2.to_f;"H%f"%(fmlwt($1)*n/awt["H"].to_f)} while fml=~/[\(\[]/
r=0
fml.scan(/([A-Z][a-z]?)([\d\.]*)/){|a,n|
n=1 if n==""
r+=awt[a].to_f*n.to_f
}
(r*1e3).round/1e3
end
しかし、やり方が汚すぎる。置換の部分を少し工夫したら、もう少し短くなった。
def fmlwt(fml)
awt=Hash[*IO.read("formula.dat").strip.split(/\s+/m)]
re=/[\(\[]([^\(\)\[\]]*)[\)\]]([\d\.]*)/
fml=$`+"H%f"%(fmlwt($1)*($2==""?1:$2.to_f)/awt["H"].to_f)+$' while fml=~re
r=0
fml.scan(/([A-Z][a-z]?)([\d\.]*)/){|a,n| r+=awt[a].to_f*(n==""?1:n.to_f)}
(r*1e3).round/1e3
end