⚗️

化学式・化学反応式の入力を楽にする Vue.js コンポーネント

2023/12/10に公開

概要

input
<cf-html convert="PbO2 + 4H+ + SO4 2- + 2e- --> PbSO4 + 2H2O"></cf-html>

このように入力した化学反応式を、

output
<div class="cf-html">
	<span class="comp">
		<span class="sbst">PbO2</span>
	</span> + 
	<span class="comp">4
		<span class="sbst">H</span>
		<span class="ion">+</span>
	</span> + 
	<span class="comp">
		<span class="sbst">SO4</span>
		<span class="ion">2−</span>
	</span> + 
	<span class="comp">2
		<span class="sbst">e</span>
		<span class="ion"></span>
	</span> -->
	<span class="comp">
		<span class="sbst">PbSO4</span>
	</span> + 
	<span class="comp">2
		<span class="sbst">H2O</span>
	</span>
</div>


output
このように変換する Vue.js コンポーネントを作った。
以下のサイトに使用例を掲載した。
https://tan-lab.net/tool/cf-html/

きっかけ

化学式(組成式、分子式)では上付き文字や下付き文字でイオンの価数や原子の数を表現したり、化学反応式では通常の文字で係数を表現したりする。

しかしこれをHTMLで記述しようとすると大変なのだ! 以下に例を示す:

<p>PbO<sub>2</sub> + 4H<sup>+</sup> + SO<sub>4</sub><sup>2-</sup> + 2e<sup>-</sup> --> PbSO<sub>4</sub> + 2H2O</p>

HTMLでは上付き文字を<sup></sup>、下付き文字を<sub></sub>というタグで囲うことで表現できるが、簡単な式ならまだしも長い式になると面倒になる。

そこで、手書きするときと同じように入力した化学式(化学反応式も)を Vue.js 側で解釈し、相当なタグを挿入したものに変換してもらうことにした。

化学式の解釈

ここでは以下の化学反応式が入力されたとして、それを解釈する。

<cf-html convert="PbO2 + 4H+ + SO4 2- + 2e- --> PbSO4 + 2H2O"></cf-html>
化学式表記のレギュレーション
  • 元素は、元素記号で表記する。電子はeと書く。
    H He NaCl
  • 組成式や分子式で元素記号の右下に書く数(比や個数を表す)はそのまま書いてよい。
    CaCl2 H2O
  • 係数は、元素記号の前に空白なしに数字で表記する。分数を使ってもよい。
    2O2 10H2O2 3/2O2
  • イオン式は、イオンの価数が1のときは元素記号の後ろに空白なしに表記する。
    4H+ 2OH- (- はハイフンマイナス)
  • イオンの価数が2以上のときは、元素記号の後ろに半角スペースを開けて表記する。
    SO4 2- Al 3+
  • 式にかっこが必要なときは、該当箇所に空白なしに表記する。
    Ca(OH)2 2[Ag(NH3)2]+
  • 化学反応式をつなぐ+-->の前後には半角スペースを開ける。
  • 沈殿、気体の発生は、式の後ろに半角スペースを開けDnUpと表記する。
    Pb(OH)2 Dn 3CO2 Up(解釈の過程でPb(OH)2↓3CO2↑に変換される)

1、化学反応式を分解する

入力された式(文字列)を␣+␣␣-->␣のあるところで分解する。

["PbO2", " + ", "4H+", " + ", "SO4 2-", " + ", "2e-", " --> ", "PbSO4", " + ", "2H2O"]

分解された要素は、化学式か、式を作る␣+␣␣-->␣のどれかとなっている。

2、イオンの価数が2以上の部分をあらかじめ<span>で囲う

["PbO2", " + ", "4H+", " + ", "SO4<span class="ion">2−</span>", " + ", "2e-", " --> ", "PbSO4", " + ", "2H2O"]
.cf-html .ion {
	font-feature-settings: "numr" 1;
	//数字を上付き文字にする
}

3、各化学式を処理する

  1. 化学式を<span class="comp">で囲う
  2. 化学式を、「係数」「係数とイオンの価数を除いた部分」「イオンの価数」に分解する。
  3. 係数が分数の場合は、そこだけ<span class="frac">で囲う
.cf-html .frac {
	font-feature-settings: "frac" 1;
	//数字を分数表示にする
}
  1. イオンの価数を<span class="ion">で囲う
    イオンの価数が2以上の場合は過程2で囲ってある。ここで囲うのはイオンの価数が1の+-の部分
  2. 化学式に( )があるときは、<span class="norm">で囲う
.cf-html .norm {
	font-feature-settings: "numr" 0, "dnom" 0;
	//かっこまで下付き文字になるのを防ぐため
}
  1. 化学式の係数を除いた部分をまとめて<span class="sbst">で囲う
.cf-html .sbst {
	font-feature-settings: "dnom" 1;
	//sbst = Substance のつもり
	//この中の数字を下付き文字にする
	//イオンの価数の部分は以前の過程で別のcssを適用させているので上付き文字になる
}

以上の過程3により、例えば過程2の要素のひとつである

"SO4<span class="ion">2−</span>"

<span class="comp">
	<span class="sbst">SO4</span>
	<span class="ion">2−</span>
</span>

に変換される。

4、処理した各化学式をつなぎ、<div>で囲って完成!

<div class="cf-html">
	<span class="comp">
		<span class="sbst">PbO2</span>
	</span> + 
	<span class="comp">4
		<span class="sbst">H</span>
		<span class="ion">+</span>
	</span> + 
	<span class="comp">
		<span class="sbst">SO4</span>
		<span class="ion">2−</span>
	</span> + 
	<span class="comp">2
		<span class="sbst">e</span>
		<span class="ion"></span>
	</span> -->
	<span class="comp">
		<span class="sbst">PbSO4</span>
	</span> + 
	<span class="comp">2
		<span class="sbst">H2O</span>
	</span>
</div>

これを作ると何がよいのか

  • 化学式の入力がクソ楽になる
  • 自動付与するタグは少しJavaScriptをいじるだけで容易に変更できる
    例えば、あらかじめ各化学物質と、それを解説した資料へのリンクをまとめたデータを用意し、Vue.js 側で自動で<a>タグを付与させると、化学反応式における物質の概要の復習が楽になる

今後の展望

今回は無機物質の式に焦点を当てたが、有機化合物では構造式を多用することになるため、構造式もいい感じに表現できるようなコンポーネントを作ってみたい。

おまけ

過程3(各化学式を処理する)で使用した正規表現

正規表現の勉強の一環として作ったのでこれが最適かは分かりません。すごく長くなりました。なんで動いているの?

function replacer(match, p1, p2, p3, p4){...}

element.replace(/^(\d+\/*\d*)*(\[*[A-Za-z0-9]+\(*[A-Za-z0-9]*\)*\d*\]*\d*)+(<.+>)*(\+$|\-$)*/g, replacer)

replacer()の各引数は表のとおり

引数 内容
p1 係数 2 2/3
p2 係数とイオンの価数を除いた部分 NaCl H2O2
p3 イオンの価数(2以上) <span class="ion">2−</span>
※過程2で<span>で囲った
p4 イオンの価数(1) + -

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/String/replace

使用フォントについて

https://rsms.me/inter/

https://rsms.me/inter/
もともとこのフォントには適当なcssを指定すると自動で調整されたフォントで表示してくれるという機能がありました。これによりきれいな最適化されたフォントで上付き・下付き文字を表示できるほか、--> と書くだけで自動で のようにつなげて表示してくれたりします。あとは見分けづらい Il を見分けやすいようなフォントにしたり出来る。

しかしこのフォントで遊んでいたところ、係数も一緒に上に付いたり下に付いたりして思い通りにならないことに気づきました。

これはどういうことかと言うと、フォント制作者の意図としては sups で上付き文字、subs で下付き文字を表現出来るのですが、これでは元素記号の小文字の部分も下付き文字になってしまうのです。

subs を適用した例

そのため本文では numr で上付き文字、dnom で下付き文字を表現しました。ただしこれでは、陰イオンの - が上付き文字にならなかったのです!

numr を適用した例

これを解決するためには、- (ハイフンマイナス)− (マイナス) に変換する必要がありました。

「お前は一般的じゃねえぞ」と指摘されている画像

ですから最初に与えられた化学式の- (ハイフンマイナス) をすべて − (マイナス) に変換することにしました。すると今度は化学反応式をつなぐ --> がきれいに繋がらなくなってしまいました!だるい!!!

矢印をつなげたいときは、−−> でなく --> とする必要がある

結局、各化学式に登場する - (ハイフンマイナス) のみ − (マイナス) に変換することにして解決しました。疲れました。

ギャラリー

沈殿ができる例

<cf-html convert="Pb 2+ + 2OH- --> Pb(OH)2 Dn"></cf-html>

錯イオンができる例

<cf-html convert="Ag2O + 4NH3 + H2O --> 2[Ag(NH3)2]+ + 2OH-"></cf-html>

色分けをした例


各化学式にclassをつけているので、cssで容易に色分けができる(色分けに意味はない)

Discussion