数式をTeXのソースに変換する

下記は数式をTeXのソースに変換するphpプログラムです。xmlで数式を受けて,xmlで変換後のソースを返すようになっています。複数の数式を変換するようになっています。

ソースをコピーして,張りつけたのですが,一部文字がおかしくなっているかも知れません。以前にバッククオートが変になっていたことがありました。

 

 

<?php
header(‘Access-Control-Allow-Origin:*’);
header(‘Access-Control-Allow-Headers:*’);
header(‘Access-Control-Allow-Methods:GET, POST, OPTIONS’);
header(‘Content-Type: text/plain’);
/*
* 試験的なプログラム。maximaの数式をtexにかえるもの。
* 式の頭から順に処理するタイプ。

* 複数の式を変換できるように変更した。式はxmlデータとしてもらう。

*/

# $sikiは以下で処理する、maximaの式

# $siki = “( 1 / 2 ) * x + m[x + 1] / y[2] + (x + 1) / (y – 3) + (x + 1) / y”;
# $siki = “((x + 1)) / (y – 3) + (x + 1) / y”;
# $siki = ” cos(x – 1) + log(y)”;
# $siki = “fun(x * y)”;
# $siki = “f[i + 1] / y^(x – 3)”;
# $siki = “bigsigma n + n^2 + cdot cdot cdot + n^k”;
# $siki = “v[0]^2 / g”;
# $siki = “x^2^z / 2”;

if ($HTTP_RAW_POST_DATA) {

parse_str($HTTP_RAW_POST_DATA);

} else {

$param1 = $_POST[“param1”];
}

//$logfile = fopen(“/var/www/html/temporary/log.txt”,”w”);
//fputs($logfile,$HTTP_RAW_POST_DATA);
//fclose($logfile);

/*
$param1 = ‘<?xml version=”1.0″ encoding=”utf-8″?><root><folder>tmp1310093593530405</folder><question><num>1</num><AnswerTest>Equal_Com_Ass</AnswerTest><SAns>3*x^2</SAns><Errors></Errors><RawMark>1</RawMark><FeedBack></FeedBack><AnswerNote></AnswerNote></question><question><num>2</num><AnswerTest>Equal_Com_Ass</AnswerTest><SAns>3*sqrt(2)</SAns><Errors></Errors><RawMark>0</RawMark><FeedBack></FeedBack><AnswerNote>[[ATEqual_com_ass: (not AlgEquiv)]]</AnswerNote></question></root>’;
*/

$xml = simplexml_load_string($param1);

foreach ($xml->question as $q) {

$num_ary[] = $q->num;

$AnswerTest_ary[] = $q->AnswerTest;

$siki_ary[] = $q->SAns;

}

//echo sizeof($siki_ary).”\n”;

$tmpxml = “”;

for ($i4q = 0; $i4q < sizeof($siki_ary); $i4q = $i4q + 1) {

$tmp = $siki_ary[$i4q];

//echo $tmp.”\n”;

if (($AnswerTest_ary[$i4q] == ‘Selection’) || ($AnswerTest_ary[$i4q] == ‘Glossary’)) {

$tex_ary[$i4q] = $tmp;

} else {

$tmp = trim($tmp);

if (preg_match(‘/[^A-Za-z0-9. ,^*\-\/+=<>()\[\]]/’,$tmp)) {

$tex_ary[$i4q] = ‘error(character)’;

} else {

$tmp4maxima=”display2d:false;load(\”mactex-utilities.lisp\”); tex(“.$tmp.”);”;

$meirei=escapeshellarg($tmp4maxima);

$awasete=”/usr/bin/maxima -q –batch-string=$meirei”;

$str = shell_exec($awasete);

if (strpos($str,’$$’)) {

//        $str_ary = explode(‘$$’,$str);
//        echo $str_ary[1].”\n”;

$tex_ary[$i4q] = changeToTex($tmp);

} else {

$tex_ary[$i4q] = ‘error(expression)’;

}

}

}

$tmpxml = $tmpxml.”<question>\n<num>$num_ary[$i4q]</num>\n”;

$tmpxml = $tmpxml.”<AnswerTest>$AnswerTest_ary[$i4q]</AnswerTest>\n”;

$tmpxml = $tmpxml.”<SAns>$siki_ary[$i4q]</SAns>\n”;

$tmpxml = $tmpxml.”<tex>$tex_ary[$i4q]</tex>\n</question>\n\n”;

}

$xml4return = <<< end_of_quote
<?xml version=”1.0″ encoding=”utf-8″?>
<root>

$tmpxml
</root>
end_of_quote;

echo ($xml4return.”\n”);

function changeToTex($siki) {

global $bf,$taihi,$pf,$power;

$siki = escapeshellarg($siki);

//echo “siki             = |$siki| \n”;

$siki = trim($siki, “‘”);

//echo “trim             ->|$siki| \n”;

$siki = ereg_replace(‘([\*/\+\-])’,’ \1 ‘,$siki); # * / + – の前後にスペースを入れる

//echo “add space */+-   ->|$siki| \n”;

$siki = ereg_replace(‘ +’,’ ‘,$siki); # スペースは2個連続しない

//echo “cut double space ->|$siki| \n”;

$siki = $siki.” “;            # 最後にスペースが必要なようだ

//echo “add space at end ->|$siki| \n”;

$nagasa = strlen($siki);
$arr = str_split($siki);

$arr[$nagasa] = ‘ ‘;
$arr[$nagasa + 1] = ‘ ‘;

# echo “長さは”.$nagasa.”\n”;

//echo “arr       -> |”.implode(“|”,$arr).”|”.”\n”;

$i = 0;

$bf = 0;    # 括弧の階層を示すフラッグ、括弧があるとフラッグが1変化する
$taihi = ”;        # @以下の要素を一時的に格納する変数
$youso[0] = ”;     # texの式のテンポラリーな入れ物
$pf = 0;    # 階乗の指数部のフラッグ
$power[0] = -1;    # 階乗のカッコがどの$bfで開始されたのかを記録する変数。

while ($nagasa – 1 >= $i) {

//echo ” \$i = $i , |$arr[$i]| \n”;

if ($arr[$i] == ‘(‘ || $arr[$i] == ‘)’ || $arr[$i] == ‘[‘ || $arr[$i] == ‘]’) {
kcount ($arr[$i],$arr[$i + 1],$arr[$i + 2],$youso);
}

if (ereg(‘[a-zA-Z0-9.]’, $arr[$i])) {
alpha ($arr[$i],$arr[$i + 1],$arr[$i + 2],$youso);
}

if ($arr[$i] == “+” || $arr[$i] == “-” || $arr[$i] == “=”) {
epm ($arr[$i],$youso);
}
if ($arr[$i] == ” “) {
space ($arr[$i],$arr[$i + 1],$youso);
}

if ($arr[$i] == “*”) {
kakeru ($arr[$i],$youso);
}

if ($arr[$i] == “^”) {
kaijyou ($arr[$i],$youso);
}

if ($arr[$i] == “/”) {
waru ($arr[$i],$youso);
}

$i = $i + 1;
}

# 最後の処理

//echo “last                |$youso[0]| pf = $pf, power = $power[$pf], bf = $bf \n”;

power_blackt_close($youso[0]);

//echo “power_blackt_close  |$youso[0]| \n”;

#preg_match(‘/cos\\\\left\(([^\\\\]*)\\\\right\)\^\{([^}]*)\}/’,$youso[0],$tmpary);
#echo “preg        |$tmpary[0]| |$tmpary[1]| |$tmpary[2]| \n”;

$youso[0] = preg_replace(‘/(cos|cos |sin|sin |tan|tan )\\\\left\((.*?)\\\\right\)\^\{([^}]*)\}/’,’\1^{\3}\left(\2\right)’,$youso[0]);

//echo “etc cos, sin        |$youso[0]| \n”;

makefrac($youso[0]);

//$youso[0] = ereg_replace(‘[\\]cdot’,’\,’,$youso[0]);

//echo ‘this$$’.$youso[0].’$$that’.”\n”;

//echo $youso[0].”\n”;

return $youso[0];

} //changeToTex

function kcount ($arr,$arr1,$arr2,&$y) {
# 括弧のカウント

global $bf,$taihi,$pf,$power;

//echo “kcount start bf = $bf, y = |$y[$bf]| taihi = |$taihi| arr = |$arr| \n”;

switch($arr) {
case ‘(‘:
$y[$bf] = $y[$bf].$taihi;
$taihi = ”;
$bf = $bf + 1;

//echo “bf change -> $bf \n”;

$y[$bf] = ”;
break;
case ‘)’:
$y[$bf] = $y[$bf].$taihi;

power_blackt_close($y[$bf]);

#echo “kcount no1 |$y[$bf]| \n”;
#$y[$bf] = ereg_replace(‘\@\^’,’^’,$y[$bf]);
#echo “kcount no2 |$y[$bf]| \n”;

makefrac($y[$bf]);

$y[$bf] = ‘\left(‘.$y[$bf].’\right)’;
$bf = $bf – 1;

//echo “bf change -> $bf \n”;

$y[$bf] = $y[$bf].$y[$bf + 1].’@’;

$y[$bf] = ereg_replace(‘(.*)[\^][\\]left[\(](.*)[\\]right[\)]’,’\1^{\2}’,$y[$bf]);
$y[$bf] = ereg_replace(‘[\\]sqrt *[\\]left[\(](.*)[\\]right[\)]’,’\sqrt{\1}’,$y[$bf]);

//echo “kcount no3 |$y[$bf]| \n”;

$taihi = ”;
break;
case ‘[‘:
$y[$bf] = $y[$bf].$taihi;
$taihi = ”;
$bf = $bf + 1;

//echo “bf change -> $bf \n”;

$y[$bf] = ”;
break;
case ‘]’:
$y[$bf] = $y[$bf].$taihi;
$taihi = ”;
makefrac($y[$bf]);

$y[$bf] = ‘_{‘.$y[$bf].’}’;
$bf = $bf – 1;

//echo “bf change -> $bf \n”;

$y[$bf] = $y[$bf].$y[$bf + 1].’@’;
break;
}

//echo “kcount end  bf = $bf, y = |$y[$bf]| taihi = |$taihi| arr = |$arr| \n”;

}

function alpha ($arr,$arr1,$arr2,&$y) {
# アルファベットと数字の処理、とにかく前の要素に継ぎ足す

global $bf,$taihi,$pf,$power;

//echo “alpha start y = |$y[$bf]| taihi = |$taihi| arr = |$arr| \n”;

$taihi = $taihi.$arr;

#    echo “alpha $taihi \n”;

# 次の文字、さらにその次の文字を調べて、応答を変える。

if ($arr1 == ‘ ‘) {
if ($arr2 == ‘(‘) {
fun ($taihi);

} else {

greek ($taihi);

$y[$bf] = $y[$bf].$taihi.’@’;

//echo “alpha no1  y = |$y[$bf]| \n”;

$taihi = ”;
}
}

if ($arr1 == ‘(‘) {
fun($taihi);
}

if ($arr1 == ‘)’ || $arr1 == ‘[‘ || $arr1 == ‘]’ || $arr1 == ‘^’ || $arr1 == ‘/’ || $arr1 == ‘+’ || $arr1 == ‘-‘ || $arr1 == ‘*’ || $arr1 == ‘=’ ) {
greek ($taihi);
}

//echo “alpha end  y = |$y[$bf]| taihi = |$taihi| \n”;

}

function fun(&$taihi) {

# 関数を認識する所、新しい関数を加えるならこの直下    。関数と認識したら@を付けない

//echo “fun startt taihi = |$taihi| \n”;

switch($taihi) {
case ‘cos’:
$taihi = ‘\cos’ ;
break;
case ‘sin’:
$taihi = ‘\sin’ ;
break;
case ‘tan’:
$taihi = ‘\tan’ ;
break;
case ‘log’:
$taihi = ‘\log’ ;
break;
case ‘sqrt’:
$taihi = ‘\sqrt’ ;
break;
case ‘Delta’:
$taihi = ‘\Delta’ ;
break;
case ‘exp’:
$taihi = ‘e^’ ;
break;

case ‘alpha’:
$taihi = ‘\alpha’ ;
break;
case ‘beta’:
$taihi = ‘\beta’ ;
break;
case ‘gamma’:
$taihi = ‘\gamma’ ;
break;
case ‘delta’:
$taihi = ‘\delta’ ;
break;
case ‘epsilon’:
$taihi = ‘\epsilon’ ;
break;
case ‘varepsilon’:
$taihi = ‘\varepsilon’ ;
break;
case ‘eta’:
$taihi = ‘\eta’ ;
break;
case ‘theta’:
$taihi = ‘\theta’ ;
break;
case ‘lambda’:
$taihi = ‘\lambda’ ;
break;
case ‘mu’:
$taihi = ‘\mu’ ;
break;
case ‘nu’:
$taihi = ‘\nu’ ;
break;
case ‘pi’:
$taihi = ‘\pi’ ;
break;
case ‘rho’:
$taihi = ‘\rho’ ;
break;
case ‘sigma’:
$taihi = ‘\sigma’ ;
break;
case ‘tau’:
$taihi = ‘\tau’ ;
break;
case ‘phi’:
$taihi = ‘\phi’ ;
break;
case ‘varphi’:
$taihi = ‘\varphi’ ;
break;
case ‘chi’:
$taihi = ‘\chi’ ;
break;
case ‘psi’:
$taihi = ‘\psi’ ;
break;
case ‘omega’:
$taihi = ‘\omega’ ;
break;

case ‘times’:
$taihi = ‘\times @’ ;
break;

case ‘pm’:
$taihi = ‘\pm @’ ;
break;
case ‘mp’:
$taihi = ‘\mp @’ ;
break;

default:
# 今のところ何もしない
}

//echo “fun end   taihi = |$taihi| \n”;

}

function greek (&$taihi) {

# ギリシャ文字などを認識する所

//echo “greek start taihi = |$taihi| \n”;

switch($taihi) {
case ‘alpha’:
$taihi = ‘\alpha’ ;
break;
case ‘beta’:
$taihi = ‘\beta’ ;
break;
case ‘gamma’:
$taihi = ‘\gamma’ ;
break;
case ‘delta’:
$taihi = ‘\delta’ ;
break;
case ‘epsilon’:
$taihi = ‘\epsilon’ ;
break;
case ‘varepsilon’:
$taihi = ‘\varepsilon’ ;
break;
case ‘eta’:
$taihi = ‘\eta’ ;
break;
case ‘theta’:
$taihi = ‘\theta’ ;
break;
case ‘lambda’:
$taihi = ‘\lambda’ ;
break;
case ‘mu’:
$taihi = ‘\mu’ ;
break;
case ‘nu’:
$taihi = ‘\nu’ ;
break;
case ‘pi’:
$taihi = ‘\pi’ ;
break;
case ‘rho’:
$taihi = ‘\rho’ ;
break;
case ‘sigma’:
$taihi = ‘\sigma’ ;
break;
case ‘tau’:
$taihi = ‘\tau’ ;
break;
case ‘phi’:
$taihi = ‘\phi’ ;
break;
case ‘varphi’:
$taihi = ‘\varphi’ ;
break;
case ‘chi’:
$taihi = ‘\chi’ ;
break;
case ‘psi’:
$taihi = ‘\psi’ ;
break;
case ‘omega’:
$taihi = ‘\omega’ ;
break;
case ‘Delta’:
$taihi = ‘\Delta’ ;
break;
case ‘hbar’:
$taihi = ‘\hbar’ ;
break;

case ‘times’:
$taihi = ‘\times’ ;
break;
case ‘pm’:
$taihi = ‘\pm’ ;
break;
case ‘mp’:
$taihi = ‘\mp’ ;
break;
case ‘cdot’:
$taihi = ‘\cdot’ ;
break;
case ‘sum’:
$taihi = ‘\sum’ ;
break;

default:
# 今のところ何もしない
}

//echo “greek end  taihi = |$taihi| \n”;

}

function epm ($arr,&$y) {
# =と+と-の処理

global $bf,$taihi,$pf,$power;

# +-を加えて区切る

//echo “epm start y = |$y[$bf]|  and taihi = |$taihi| arr = |$arr| \n”;

$y[$bf] = $y[$bf].$taihi.$arr.’@’;
$taihi = ”;

//echo “epm end  y = |$y[$bf]|  and taihi = |$taihi| arr = |$arr| \n”;

}

function space ($arr,$arr1,&$y) {
# スペースの処理

global $bf,$taihi,$pf,$power;

# スペースを加えて区切る、関数名と括弧の隙間なら区切らない。sin (x)など。

//echo “space no1 |$y[$bf]|  and taihi = |$taihi| \n”;

$y[$bf] = $y[$bf].$taihi;

$taihi = “”;

if ($arr1 == ‘(‘) {

if (ereg(‘@$’,$y[$bf])) {

$y[$bf] = $y[$bf].$arr.’@’;
//echo “space no2 |$y[$bf]| \n”;

} else {
$y[$bf] = $y[$bf].$arr;        //関数と判断して@をつけない
//echo “space no3 |$y[$bf]| \n”;
}

} else {
if ($pf > 0 and $power[$pf] == $bf) {

power_blackt_close($y[$bf]);

#            階乗のカッコが閉じたのでmakefracなども? … ここでは必要なかった。
#            ereg(‘\{([^{]*)\}@$’,$y[$bf],$naka); //最小の長さの{…}を抜き出す
#            echo “naka 1 = |$naka[1]| \n”;
#            makefrac($naka[1]);
#            $naka[1] = ‘{‘.$naka[1].’}@’;
#            echo “naka 2 = |$naka[1]| \n”;
#            $y[$bf] = ereg_replace(‘\{([^{]*)\}@$’,$naka[1],$y[$bf]);

$y[$bf] = $y[$bf].” @”;

} else {
$y[$bf] = $y[$bf].$arr.’@’;
}

//echo “space no4 |$y[$bf]| \n”;

}

//echo “space end |$y[$bf]| \n”;

}

function power_blackt_close (&$yy) {

#    階乗のカッコを閉じる

global $bf,$taihi,$pf,$power;

//echo “power blacket close start yy = |$yy| \n”;

#    @を削って

if (ereg(‘@$’,$yy)) {

$yy = substr($yy, 0, strlen($yy) – 1);

//echo ” cut @ at the end  yy = |$yy| \n”;
}

while ($power[$pf] >= $bf) {

$yy = $yy.’}’;

$power[$pf] = -1;

$pf = $pf – 1;

//echo ”   power down pf = $pf \n”;

}

//echo “power blacket close end  yy = |$yy| \n”;

}

function kakeru ($arr,&$y) {
# *の処理、とにかく区切る

global $bf,$taihi,$pf,$power;

//echo “kakeru start y = |$y[$bf]|  and taihi = |$taihi| arr = |$arr| \n”;

$y[$bf] = $y[$bf].$taihi.’\cdot ‘.’@’;

$taihi = ”;

//echo “kakeru end  y = |$y[$bf]|  and taihi = |$taihi| arr = |$arr| \n”;

}

function kaijyou ($arr,&$y) {
# ^の処理

global $bf,$taihi,$pf,$power;

//echo “kaijyou start y = |$y[$bf]|  and taihi = |$taihi| arr = |$arr| \n”;

$y[$bf] = $y[$bf].$taihi;

//echo ”       y = |$y[$bf]| \n”;

#    後ろに付いている@とスペースを削って^を付け足す

while (ereg(‘@$’,$y[$bf]) || ereg(‘ $’,$y[$bf])) {

$y[$bf] = substr($y[$bf], 0, strlen($y[$bf]) – 1);

//echo ”       y = |$y[$bf]| \n”;
}

$taihi = ”;

$y[$bf] = $y[$bf].’^{‘;

$pf = $pf + 1;
$power[$pf] = $bf;

//echo “kaijyou end y = |$y[$bf]| \n”;

//echo “Power up pf = $pf , bf = $bf \n”;
}

function waru ($arr,&$y) {
# /の処理

global $bf,$taihi,$pf,$power;

//echo “waru start y = |$y[$bf]|  and taihi = |$taihi| arr = |$arr| \n”;

$y[$bf] = $y[$bf].$taihi.’/’.’@’;

$taihi = ”;

//echo “waru end   y = |$y[$bf]|  and taihi = |$taihi| arr = |$arr| \n”;

}

function makefrac (&$yy) {

# 分数をつくるところ。割る記号と割る記号の間に+ー*=があると別な分数とみなす。そうでなければ同じ分数として取り扱う。

//echo “start makefrac yy = |$yy| \n”;

$tmparr = split(‘@’,$yy);
$tmpnagasa = sizeof($tmparr);
$tmparr[$tmpnagasa] = ”;

$j = 1;
$aida = 1;

while ($j <= $tmpnagasa – 2) {

if ($tmparr[$j] == ‘=’ || $tmparr[$j] == ‘+’ || $tmparr[$j] == ‘-‘ ||$tmparr[$j] == ‘\cdot ‘) {
$aida = $aida + 1;
}

if ($tmparr[$j] == ‘/’) {

$tmparr[$j] = ”;

if ($aida >= 1) {

$k = $j – 1;
while ($tmparr[$k] == ” | $tmparr[$k] == ‘ ‘) {
$k = $k – 1;
}

//echo ”  no1 |$tmparr[$k]| \n”;

$tmparr[$k] = ereg_replace(‘^[\\]left[\(](.*)[\\]right[\)]$’,’\1′,$tmparr[$k]);

#                echo “no2 |$tmparr[$k]| \n”;

#                $tmparr[$k] = ereg_replace(‘(.*)[\\]left[\(]([^+-]*)[\\]right[\)]$’,’\1 \2′,$tmparr[$k]);

//echo ”  no3 |$tmparr[$k]| \n”;

$tmparr[$k] = ‘\frac{‘.$tmparr[$k].’}’;

//echo ”  no4 |$tmparr[$k]| \n”;

$k = $j + 1;
while ($tmparr[$k] == ” | $tmparr[$k] == ‘ ‘) {
$k = $k + 1;
}

$tmparr[$k] = ereg_replace(‘^[\\]left[\(](.*)[\\]right[\)]$’,’\1′,$tmparr[$k]);
#                $tmparr[$k] = ereg_replace(‘(.*)[\\]left[\(]([^+-]+)[\\]right[\)]$’,’\1 \2′,$tmparr[$k]);

$tmparr[$k] = ‘{‘.$tmparr[$k].’}’;

//echo ”  no5 |$tmparr[$k]| \n”;

$aida = 0;

} else {

$k = $j – 1;
while ($tmparr[$k] == ” | $tmparr[$k] == ‘ ‘) {
$k = $k – 1;
}

if (ereg(‘[\+\-]’, $tmparr[$k])) {

$tmp = ereg_replace(‘{(.+)}’,’\left(\1\right)’,$tmparr[$k]);
} else {

$tmp = ereg_replace(‘{(.+)}’,’\1′,$tmparr[$k]);
}

$m = $j + 1;
while ($tmparr[$m] == ” | $tmparr[$m] == ‘ ‘) {
$m = $m + 1;
}

$tmparr[$k] = ‘{‘.$tmp.’ \cdot ‘.$tmparr[$m].’}’;

//echo ”  no6 |$tmparr[$k]| \n”;

$tmparr[$m] = ”;
$aida = 0;
}
}

$j = $j + 1;
}

$yy = implode(“@”,$tmparr);        #バグ取りのため、本当は@をはさむ必要はない。

//echo “end   makefrac yy = |$yy| \n”;

$yy = ereg_replace(‘@’,”,$yy);
$yy = ereg_replace(‘ +’,’ ‘,$yy); # スペースは2個連続しない
$yy = trim($yy);

//echo “stop  makefrac yy = |$yy| \n”;

}

?>