2009年
12月
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31

setup diary

2007|12|
2008|01|02|03|04|05|06|07|08|09|10|11|12|
2009|01|02|03|04|05|06|07|08|09|10|11|12|
2010|01|02|03|04|05|06|07|08|09|10|11|12|
2011|01|02|03|04|05|06|07|08|09|10|11|12|
2012|01|02|03|04|05|06|07|08|10|11|12|
2013|01|02|03|04|05|06|07|08|09|10|11|12|
2014|01|02|03|04|06|08|11|
2015|01|02|03|04|05|06|07|08|10|11|12|
2016|01|02|03|04|05|06|07|08|09|10|11|12|
2017|01|02|03|04|05|06|07|08|09|10|11|12|
2018|01|02|03|04|05|06|07|08|09|10|11|12|
2019|01|02|03|04|05|06|07|08|09|10|11|12|
2020|01|02|03|04|05|06|07|08|09|10|11|12|
2021|01|02|03|04|05|06|07|08|09|10|11|12|
2022|01|02|03|04|05|06|07|08|09|10|11|12|
2023|01|02|03|04|05|06|07|08|09|10|11|

2009-12-19 TeXの化学式

_ rubyで変換

TeXで文章を書くときに面倒なのが、化学式である。ZnCr2O4と書きたいときに、$ZnCr_2O_4$と書くと、元素記号が斜体になってしまうので、ZnCr$_2$O$_4$と書く人が多いようだ。しかし、私の考えでは、元素記号も「式」なので、数式モードにするべきであり、${\rm ZnCr}_2{\rm O}_4$と書いている。しかし、これをいちいち書くのは面倒である。

そこで、$ZnCr2O4$と書いておくと、それを自動で変換してくれるような scriptをrubyで書いて、それで変換している。

str.gsub!(/\$([A-Z][a-z]?)([\d\.]*)\$/){"${\\rm #{$1}}_{#{$2}}$"}

とすると、化学式っぽいものを変換してくれる。元素記号は[A-Z][a-z]?と表して、この後に数字がくるかもしれないとしている。この例は一元素用で、二元素や三元素などのものも羅列しておかなければならない。また、$P$と書いたときに、燐なのか圧力なのかが分からないので、斜体にならず元素と思われてしまう。このような場合には、$P $などと余分のスペースを入れて区別している。化学式には余分なスペースは入れないようにするのである。

しかし、この手法には他にも不便な点がある。$MCr2O4$としたときには、Mは斜体にしたいのに、正体になってしまう。また、$Zn1-xCdxCr2O4$なども判定できない。こういった場合には、手で書かなければならない。

せっかくなので、少し凝ったscriptでそれらの解決を試みた。とりあえず作ってみたのがこれ。

Element='([A-Z][a-z]?)'
Number='([\d\.\+\-a-z]*)'
def element(str)
  "AMRTXQ".split(//).include?(str)? str:"{\\rm %s}"%str
end
def subscript(str)
  "_{%s}"%str
end
d=<<DATA
$ZnCr2O4$ is one of a chromium spinels $MCr2X4$.
$Cu1-xNix$ is an alloy of $Cu$ and $Ni$.
DATA
d.gsub!(/(\$(#{Element}#{Number})+\$)/){
  str0=$1
  num=str0.gsub(/[^A-Z]/){""}.size
  str="$"
  m=/\$#{(Element+Number)*num}\$/.match(str0)
  num.times{|i| str+=element(m[i*2+1])+subscript(m[i*2+2]) }
  str+"$"
}
puts d

数字のところには、小文字のアルファベットと+-を入れられるようにした。そして、AMRTXQは斜体になるようにした。そして、いくつの元素の場合でも対応できるようになった。

まあ、これでそれなりに便利になるだろうが、まだ問題がある。まず、$P$のような場合は今までと同様にだめである。それから、$Zn2+$は2+が下付きになってしまう。これは、あらかじめイオンを処理してから、化学式を処理すれば問題ない。

str.gsub!(/([A-Z][a-z]?)(\d?\+)/){"{\\rm #{$1}}\^{#{$2}}"}

最後に残った問題は$AB2O4$という場合である。この場合に、Bは硼素を表しているのか、複数の元素を表しているのかは、自明ではない。Aがなければ、ぼほ確実に硼素なのだろうし、Aがあれば後者の可能性が高い。そのような処理を組み込んでも良いのかも知れないが、それは面倒なので、今回はBは常に硼素と解釈することにした。

_ 2010.1.21追記

ローマンの指定が誤っていたので、訂正しました。