pirika logo

ホームページ Pirikaで化学 ブログ 業務案内 お問い合わせ
Pirikaで化学トップ 情報化学+教育 HSP 化学全般
情報化学+教育トップ 情報化学 MAGICIAN MOOC プログラミング
MAGICIANとは、材料ゲノム(Materials Genome)、材料情報学(Materials Informatics)、情報化学(Chemo-Informatics)とネットワーク(Networks)を結びつけて(Associate)いかれる人材です。
プログラミング・トップ 親子で JavaScript演習 化学系 HSPiP用

化学系プログラミング > Javascript化学系演習 > 分子量計算機

2021.2.10改訂(元2004.7.6)

分子量を計算します。テキストフィールドに CH3CH2OH,CHF2CF2CCl2Fのような分子式を入れ、[計算]をクリックしてください。

分子式: 
 

H-Caまで使えます。

メチル基(Me)、エチル基(Et)、フェニル基(Ph)も使えます。
N(CH3)3のような表記もOKです。

http://homepage.mac.com/mike1336/md/mike.html
にオリジナルがありましたが、現在(2021.2)は閉鎖されているようです。

プログラム

このようなソフトをブラウザー上で動かす時に必要な要素を説明します。

表示部分

HTMLのフォームで定義します。

<form name="myForm">
  <p>分子式:  
    <input type="text" name="siki" size=30 >
    <br>
    <input type="button" value=" 計算 " onClick="calc(this.form)">
      
    <input type="text" name="answer" size=20 >
  </p>
</form>

要素としては分子式入力用のテキスト・フィールドが1つ、計算を実行させるボタンが1つ、分子量の計算結果をいれるテキスト・フィールドが1つ、あります。

テキスト・フィールドは次のようになります。

<input type="text" name="XXX" size=YY >   

この時のnameには、フォーム要素の値として、form.XXX.valueでアクセスできるようになります。

ボタンが押されると、Javascriptのプログラムが実行されます。それはHTMLの中に別に記載されます。(後述)

<input type="button" value=" 計算 " onClick="calc(this.form)">

ボタンのvalueが計算というのも不思議ですが、ボタンについている名前になります。
ボタンが押された時実行されるプログラムはcalc(this.form)になります。
カッコの中にthis.formとあるのは、フォームの中にある要素にプログラムの側からアクセスできるようにするためです。

JavaScriptのプログラム

JavaScriptのプログラムはHTMLの中に書き込んでしまっても良いですし、別ファイルにして読み込んでも良いです。
ここでは、HTMLの中に書き込む方法を説明します。

基本構成は次のように最初の2行で、スクリプトとしてJavaScriptを使うと宣言して、最後の2行でそれを閉じています。
おまじないのようなものですので、そのまま覚えます。

<script language="JavaScript">
<!--
var XXX

function YYY(){
var ZZZ

}

// -->
</script>

var XXXとというのは変数 XXXを宣言(使えるように)する事です。
function(関数)の中に無い変数はグローバル変数と言って、他のfunctionの中で自由に使えます。
それに対して、function(関数)の中にある、var ZZZは、その関数の中だけで使えます。ローカル変数と言います。

他の関数に値を受け渡すこともできます。

フォームとJavaScriptの連携部分

フォームの部分で分子式を受け取り、JavaScriptで解析を行い、結果の分子量をフォームに表示させます。
その連携部分をJavaScriptで書きます。

function calc(form) {
  var str, s;
  str = form.siki.value;
  form.answer.value = "?";
  s = work(str);
  form.answer.value = 0.01*Math.floor(100.0*s+0.5);
}

この関数、calc(form)は計算ボタンが押された時に最初に呼ばれる関数です。
onClick="calc(this.form)"で呼ばれているので、form要素を関数の中で自由に使えます。
str = form.siki.value; でフォーム中のテキスト・フィールドsikiの値valueをstrに代入します。ここで、str変数には分子式が代入されます。

そして、s = work(str);で実際にJavaScriptで解析の仕事をするwork関数に分子式strが送られます。
work関数は仕事が終わると、結果を返す関数で、結果をsに代入します。

0.01*Math.floor(100.0*s+0.5) sは分子量の値ですが、それを100倍して0.5を足して、小数点以下を切り捨て(Math.floor)て0.01をかける。これは、小数点以下2桁まで表示する時のおまじないです。Math.roundで丸め込みでもいいです。
そしてこの答えを、フォームのanswerテキストフィールドの値に代入すると結果が表示されます。

文字列解析

work関数は次のようになります。
ちょっと、ごちゃごちゃしています。

function work(st) {
  var p, s, ss, c, chm1;
  p = 1;
  ss = st;
  chm1 = "A";
  s ="";
  for (p=0; p<st.length; p++) {
    ch = ss.substring(p,p+1);
    if (ch=="]") { c=")"; }
    if (isLower(ch)>=0) { c=ch;}
    if (isUpper(ch)>=0) { c="+w"+ch;  }
    if (ch=="(") { c="+"+ch; }
    if (ch=="[") { c="+("; }
    if (isNum(ch)>=0) { 
      if (isNum(chm1)>=0) {c=ch;  }
      else {c="*"+ch; }
    }
    s = s + c;
    chm1 = ch; 
  }
  //document.write(s); 
  return eval(wdada+s)
}

ゆっくり、何がしたいか考えてみましょう。

分子式解析の基本:

原子記号とその個数が文字列に記載
→文字と数字の分離

数字は1つの場合記載しない
→大文字ー大文字連鎖、小文字ー大文字連鎖の場合は数字は1

原子記号は大文字で始まる1文字だけの場合と、続く小文字が一文字の2種類ある
→大文字の後に小文字があるか調べる

慣例的に、CH3をMe, C2H5をEt、C6H5をPhと記載する事がある。
→擬似的にMe,Et,Phを原子として扱う。

()[]で括られている場合がある。
→[]は()に変換する。カッコの後ろが数字なら、カッコの中の分子量を数字倍する。

一番処理が大変なのは、カッコの取り扱いです。 このプログラムの作者は、とてもトリッキーなやり方でクリアーしています。

分子量計算式

先ほどの解析の基本を使いながら、分子式を1文字目から見ていきます。
ss.substring(p,p+1)とすると、ssの文字列の、p番目からp+1番目、つまり1文字を取り出します。
それを解析して分子量を計算する計算式に置き換えていきます。

例えば、CH3CH2OHの場合 wC+wH3+wC+wH2+wO+wH の文字列に変換します。
こうした文字列にwC=12.01などweightを与えれば分子量が計算できます。

そして、[であったら(に、]であったら)に変換します。これは、計算式の中にでは[ ]は使えないからです。
N(CH3)3の場合に、
wN+(wC+wH3)3
に変換すれば、カッコの深さや多重カッコにも対応できます。

大文字、小文字、数字の認識はis関数を使います。
例えば、小文字の文字列strLower を用意します。

strLower = "abcdefghijklmnopqrstuvwxyz)";

function isLower(s) {
  return (strLower.indexOf(s))
}

そして、例えば、Naがあった場合、小文字のaがあるかを調べるのに、 isLower("a")関数で、strLower.indexOf("a") indexOfを調べるとstrLowerの文字列の中の何番目に"a"があるか答えてくれます。
その文字がなければ、-1が返ります。

大文字や数字も同様です。
数字の時には、10進法で1桁以上があり得ます。
一つ前の文字をchm1に保存しておいて、chm1が数字なら単純に継ぎ足し、chm1が数字でなければ、*を置いてから数字にします。

これを文字ひとつづつ繰り返せば計算式 s が得られます。

分子量の計算

ここで得られた計算式は、JavaScriptの文法の計算式になります。
つまり、

function CalcMW(){
var MW;
var wN=14.01;
var wC=12.01;
var wH=1.01;
MW=wN+(wC+wH*3)*3;
return(MW);
}

とやればCalcMWはN(CH3)3の分子量を返してくれます。
しかし、計算したい式は分子式によって常に変化します。

そこで、wXyと計算式 s をeval関数で、実行させてしまいます。

eval 関数は

function Do(){
return(answer);
}

をダナミックに代行するような関数と言えます。

最終的なプログラム

最終的なJavaScriptのプログラムは次のようになります。

<script language="JavaScript">
<!--
strLower = "abcdefghijklmnopqrstuvwxyz)";
strUpper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
strNum = "0123456789";

wdada = "wH=1.01,wLi=6.94,wBe=9.01,wB=10.81,wC=12.01,"
wdada += "wN=14.01,wO=16.00,wF=19.00,wNa=22.99,wMg=24.31,";
wdada += "wAl=26.98,wSi=28.09,wP=30.97,wS=32.06,wCl=35.45,";
wdada += "wK=39.10,wCa=40.08,wPh=77.11,wEt=29.07,wMe=15.04,";

function isLower(s) {
  return (strLower.indexOf(s))
}

function isUpper(s) {
  return (strUpper.indexOf(s))
}

function isNum(s) {
  return (strNum.indexOf(s))
}

function work(st) {
  var p, s, ss, c, chm1;
  p = 1;
  ss = st;
  chm1 = "A";
  s ="";
  for (p=0; p<st.length; p++) {
    ch = ss.substring(p,p+1);
    if (ch=="]") { c=")"; }
    if (isLower(ch)>=0) { c=ch;}
    if (isUpper(ch)>=0) { c="+w"+ch;  }
    if (ch=="(") { c="+"+ch; }
    if (ch=="[") { c="+("; }
    if (isNum(ch)>=0) { 
      if (isNum(chm1)>=0) {c=ch;  }
      else {c="*"+ch; }
    }
    s = s + c;
    //sというのが計算式になる。おもしろいやり方だね。
    chm1 = ch; 
  }
  //document.write(s); 
  return eval(wdada+s)
}

function calc(form) {
  var str, s;
  str = form.siki.value;
  form.answer.value = "?";
  s = work(str);
  form.answer.value = 0.01*Math.floor(100.0*s+0.5);
}

// -->
</script>

課題

  1. 現在のものは、H-Caまでしか計算できません。これを拡張してください。その際に、小数点3桁まで計算するように拡張してください。
  2. Pr(プロピル基)、Bu(ブチル基)、Pen(ペンチル基)、Hex(ヘキシル基)が使えるように拡張してください。
  3. Smilesの構造式から分子量を計算する、別の新しい分子量計算機を作成してください。(水素を補完しなくてはならない。式中の数字は環を表すので、数字の取り扱いを変えなくてはならない。)

3は難易度が高いです。


Copyright pirika.com since 1999-
Mail: yamahiroXpirika.com (Xを@に置き換えてください) メールの件名は[pirika]で始めてください。