|
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