Google Chart APIの文字数制限を回避するために…

PukiWikiの数式プラグインをアップデートしました.
ダウンロードはこちらのページからお願いします.

この数式プラグインは Google Chart API を使っているのでサーバに TeX 環境を構築する必要がないというメリットがあるのですが,
Google Chart API の文字数制限が200字なので長い数式が書けないという欠点もあります.
その欠点を少しでも緩和しようと頑張ってみました.

無駄なスペースを省く

文字数には当然スペースもカウントされてしまいますが,TeXの数式にはスペースが意味を持つ部分と持たない部分があります.
私の知る限り,スペースが意味を持つのは次の場合だけかと思います.

1. ‘'の後のスペース
これはスペースを表現するための表記なので当然ですね

2. ‘\alpha’などの後のアルファベットとの間にあるスペース
‘\alpha a’などと表記された場合,’αa’を意味するので’\alphaa’のようにスペースを取り除いてはいけません
が,’\alpha \beta’のようにスペースの後にアルファベット以外が続く場合はスペースを取り除いても問題ありません

3. ‘\mbox{}’内のスペース
\mboxの中の内容はそのまま出力されます

というわけで,これらのスペース以外を全て取り除きます

<?php
// $eq には数式が格納されている
$eq = str_replace('\\ ', "\\\n", $eq);
$eq = preg_replace(array('/\\\\mb(?:o|ox)?\s*{(.*?)}/e', '/(\\\\[a-zA-Z]+)\s+([a-zA-Z])/'),
                   array("'\\mb{'.str_replace(' ', \"\n\", '$1').'}'", "$1\n$2"), $eq);
$eq = str_replace(array(' ', "\n"), array('', ' '), $eq);
?>

受け取る文字列には改行が含まれないので,取り除いてはいけないスペースを一旦改行文字 (LF) に変換して,
その後でスペースを全て取り除き,改行文字をまたスペースに戻しています.
2010/11/25 追記:’\‘で改行になるので,str_replace(‘\ ‘, “\\n”, $eq) よりも preg_replace(‘/(?<!\\)\ /’, “\\n”, $eq) とかにすべきですね
2010/11/26 追記:’\\ ‘のような場合はスペースを残さないといけないので,preg_replace(‘/((?:\\))\ /’, “$1\\n”, $eq) とかにすべきですかね…
2011/02/03 追記:たぶんこれが正解ですね. preg_replace(‘/(?<!\\)((?:\\\\)
)\\ /’, “$1\\n”, $eq)

省略できるものは省略する

Google Chart API の仕様なんですが,\theta は \th と表記することが可能です.
っで,何が省略可能なのか適当に調べてみました.
といっても TeX の数式にどのような記号(?)があるかよくわからないのでこのページに載っているもののみを対象としました.

<?php
$texURI = 'http://meta.wikimedia.org/wiki/%E3%83%98%E3%83%AB%E3%83%97:%E6%95%B0%E5%BC%8F%E3%81%AE%E6%9B%B8%E3%81%8D%E6%96%B9';
$ch = curl_init($texURI);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$content = curl_exec($ch);
curl_close($ch);
// \hoge という表現を抽出
preg_match_all('/(?:<code>|\G).*?(\\\\[\w^]+(?:\{[\w\s]+\}[\w\^_]*)*)(?:<\/code>|\s)/', $content, $matches);
$symbols = array_unique($matches[1]);

$apiURI ='http://chart.apis.google.com/chart?cht=tx&chl=';
// 省略前の画像の保存ディレクトリ
$originDir = 'origin';
mkdir($originDir);
// 省略後の画像の保存ディレクトリ
$shortDir = 'short';
mkdir($shortDir);
// 省略前と省略語の対応関係をCSVで保存
$csv = fopen('./correspondence.csv', 'w');
// ブログ作成用データ
$hateda = fopen('./hateda.txt', 'w');
foreach ($symbols as $symbol) {
    preg_match('/\\\\([a-zA-Z]+)((?:[\^_]*\{[\w\s]+\}[\w\^_]*)*)/', $symbol, $matches);
    $name = $matches[1];
    $filepath = "$originDir/$name.png";
    $imgURI = $apiURI . urlencode($symbol);
    if (!file_exists($filepath)) {
        $ch = curl_init($imgURI);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        $teximg = curl_exec($ch);    
        curl_close($ch);
        if(substr($teximg, 1, 3) == 'PNG'){
            $f = fopen($filepath, 'w');
            fwrite($f, $teximg);
            fclose($f);
        } else {
            continue;
        }
    }

    // \hoge の場合, \h, \ho, \hog で画像を取得してみる    
    for ($i = 1, $len = strlen($name); $i < $len; $i++) {
        $str = substr($name, 0, $i);
        $imgURI = $apiURI . urlencode('\\'.$str.$matches[2]);
        $ch = curl_init($imgURI);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        $tmpimg = curl_exec($ch);
        curl_close($ch);

        // 省略前の画像の内容と一致すれば保存してブレイク
        if(strcmp($teximg, $tmpimg) === 0) {
            $f = fopen("$shortDir/$str.png", 'w');
            fwrite($f, $tmpimg);
            fclose($f);
            echo $name, ' --> ', $str, "\n";
            fwrite($csv, "$name,$str\n");
            fwrite($hateda, "| $symbol | \\$str${matches[2]} | <img src=\"$imgURI\"> |\n");
            break;
        }
    }
}
fclose($list);
fclose($hateda);
?>

省略可能なものは以下のとおりのようです.

オリジナル 省略表記 画像
\hat{a} \h{a}
\tilde{a} \til{a}
\bar{a} \ba{a}
\ddot{a} \dd{a}
\dot{a} \do{a}
\approx \ap
\simeq \sime
\equiv \eq
\mbox{or} \mb{or}
\neq \ne
\propto \prop
\ntriangleleft \nt
\ntrianglelefteq \nt
\ntriangleright \ntriangler
\ntrianglerighteq \ntriangler
\oplus \op
\bigoplus \bigop
\times \tim
\otimes \ot
\bigotimes \bigot
\cdot \cd
\circ \ci
\bullet \bu
\star \st
\frac{1}{2} \fr{1}{2}
\sin \si
\cos \co
\tan \ta
\sec \se
\csc \cs
\arcsin \arcs
\arccos \arc
\arctan \arct
\operatorname{sh}o \ope{sh}o
\lim \li
\limsup \lims
\liminf \limin
\min \mi
\max \ma
\sup \su
\exp \e
\lg \l
\log \lo
\ker \k
\deg \de
\gcd \gc
\hom \ho
\arg \ar
\dim \di
\pmod{m} \pmo{m}
\nabla \na
\partial \pa
\forall \fo
\exists \exi
\empty \em
\emptyset \em
\subset \sub
\subseteq \subsete
\supset \sups
\supseteq \supsete
\bigcap \bigca
\cup \cu
\bigcup \bigc
\biguplus \bigu
\setminus \set
\sqsubset \sqs
\sqsubseteq \sqs
\sqsupset \sqsup
\sqsupseteq \sqsup
\sqcap \sqca
\sqcup \sqc
\bigsqcup \bigsq
\wedge \we
\bigwedge \bigw
\bigvee \bigv
\sqrt{2} \sq{2}
\Diamond \Di
\triangle \tri
\perp \pe
\leftarrow \lefta
\rightarrow \ri
\leftrightarrow \leftr
\longleftarrow \longl
\longrightarrow \longr
\mapsto \map
\nearrow \nea
\searrow \sea
\swarrow \sw
\nwarrow \nw
\uparrow \upa
\downarrow \dow
\updownarrow \upd
\rightharpoonup \righth
\rightharpoondown \rightharpoond
\leftharpoonup \lefth
\leftharpoondown \leftharpoond
\Leftarrow \Le
\Rightarrow \Ri
\Leftrightarrow \Leftr
\Longleftarrow \Longl
\Longrightarrow \Longr
\Longleftrightarrow \Longleftr
\Uparrow \Upa
\Downarrow \Do
\Updownarrow \Upd
\longleftrightarrow \longleftr
\dagger \da
\ddagger \dda
\smile \smi
\frown \fro
\triangleleft \trianglel
\triangleright \triangler
\infty \inft
\bot \bo
\vdash \vd
\imath \imat
\ell \el
\Re \R
\Im \I
\wp \w
\clubsuit \cl
\spadesuit \sp
\flat \fla
\natural \nat
\sharp \sh
\boxdot \boxd
\curlywedge \curlyw
\curlyvee \cur
\jmath \j
\surd \sur
\ast \as
\uplus \up
\diamond \dia
\bigtriangleup \bigt
\bigtriangledown \bigtriangled
\ominus \omi
\oslash \os
\odot \od
\bigcirc \bigci
\amalg \am
\prec \pr
\succ \suc
\preceq \prece
\succeq \succe
\dashv \das
\asymp \asy
\parallel \para
\stackrel{a}{z} \stac{a}{z}
\prime \pri
\overline{bc} \overl{bc}
\underline{bc} \un{bc}
\vec{a} \v{a}
\widehat{bc} \wideh{bc}
\oint_{C} \oi_{C}
\Gamma \G
\Delta \De
\Theta \T
\Lambda \Lam
\Xi \X
\Sigma \Si
\Upsilon \U
\Phi \Ph
\Psi \Ps
\alpha \al
\beta \be
\gamma \ga
\delta \del
\epsilon \ep
\zeta \z
\eta \et
\theta \th
\iota \io
\kappa \ka
\lambda \lam
\mu \m
\nu \n
\xi \x
\pi \p
\rho \rh
\sigma \sig
\upsilon \ups
\phi \ph
\chi \ch
\psi \ps
\omega \om
\varepsilon \vare
\vartheta \vart
\varpi \va
\varrho \varr
\varsigma \vars
\varphi \varph
\mathbb{A} \mathb{A}
\mathit{A} \mat{A}
\mathrm{A} \mathr{A}
\mathfrak{A} \mathf{A}
\mathcal{A} \mathc{A}
\aleph \ale
\right \ri
\quad \qu
\lbrace \lbr
\rbrace \rbr
\qquad \qq
\mbox{ } \mb{ }

※\right -> \ri はバグです.tex.inc.php ではこれに加えて \hspace -> \hs, \begin -> \beg の変換も行います

というわけで,tex.inc.phpでは字数制限の200字を超えた場合に省略表記に変換するようにしました.
私のPukiWikiにある数式で試したところ,100字超の数式であれば無駄なスペースを削除して省略表記を使うことで平均約1割削減できました.
つまり約220字まで記述することができることになります.

そんなわけで,よかったら使ってくださいね!