• ベストアンサー

n次式を手入力から自動変換にしたい

n次式を手入力から自動変換にしたい。 たとえば、 var y = x³(x-5)² / 27; 現在は、式を手入力しています。 function test1(x){ var y = x * x * x * (x-5) * (x-5) / 27; return y; } これを自動変換して、次のようにしたい。 function test2(x){ var y = □□□□□□□□; return y; } for~ループ、または while文などを使ってできますか? わかる方、ご教示ください。

質問者が選んだベストアンサー

  • ベストアンサー
  • _kappe_
  • ベストアンサー率68% (1606/2337)
回答No.9

真面目に字句解析・構文解析を行うと数百行規模のコードになりそうと回答No.4で書きましたが、真面目に解析しないいいかげんなプログラムを書いてみました。これでも60行以上あります。 上付き数字で書かれたべき乗は**演算子に変換します。 例として、transform("a¹²b(c+3)⁴(50 - de)")を実行すると結果として"a**12*b*(c+3)**4*(50 - d*e)"という文字列が返ります。 思ったように変換できないパターンがあっても悪しからず。 var CharKind = { Numeric : 0, Variable : 1, LeftParen : 2, RightParen : 3, SuperscriptNum : 4, Whitespace : 5, Other : 6 } function transform(s) { ret = ""; prevKind = CharKind.Other; for (i = 0; i < s.length; i++) { kind = CharKind.Other; c = s.charAt(i); if ('0' <= c && c <= '9') { kind = CharKind.Numeric; } else if ('a' <= c && c <= 'z') { kind = CharKind.Variable; } else if (c == '(') { kind = CharKind.LeftParen; } else if (c == ')') { kind = CharKind.RightParen; } else if ((idx = "⁰¹²³⁴⁵⁶⁷⁸⁹".indexOf(c)) >= 0) { kind = CharKind.SuperscriptNum; c = idx.toString(); } else if (c == ' ') { kind = CharKind.Whitespace; } switch (prevKind) { case CharKind.Numeric: if (kind == CharKind.Variable || kind == CharKind.LeftParen) { ret += "*"; } break; case CharKind.Variable: if (kind == CharKind.Variable || kind == CharKind.LeftParen) { ret += "*"; } else if (kind == CharKind.SuperscriptNum) { ret += "**"; } break; case CharKind.RightParen: if (kind == CharKind.Numeric || kind == CharKind.Variable || kind == CharKind.LeftParen) { ret += "*"; } else if (kind == CharKind.SuperscriptNum) { ret += "**"; } break; case CharKind.SuperscriptNum: if (kind == CharKind.Variable || kind == CharKind.LeftParen) { ret += "*"; } break; } ret += c; if (kind != CharKind.Whitespace) { prevKind = kind; } } return ret; }

retorofan
質問者

お礼

ご回答ありがとうございます。 研究させて頂きます。

すると、全ての回答が全文表示されます。

その他の回答 (8)

  • kkkkkm
  • ベストアンサー率66% (1747/2623)
回答No.8

> かなり複雑になるようですね。 JSEP.JSを使う方はよくわかりませんが JSEP.JSを使わずに str = str.replace(/(\d)\(/g, "$1*("); //これは単純に(の前に*を入れている ↑のところで 式を左から順に調べて 文字が、数値、+、-、*、/、(、)、半角スペースではない もしくは 次の文字が、数値、+、-、*、/、)、半角スペースではない もしくは 文字が、)、かつ次の文字が数値である 場合に文字と次の文字の間に「*」を入れるようにstrを作成すればいけそうな感じなのですが、いまいち自信はありません。

retorofan
質問者

お礼

ご回答ありがとうございます。 研究させて頂きます。

すると、全ての回答が全文表示されます。
  • kkkkkm
  • ベストアンサー率66% (1747/2623)
回答No.7

イメージです。 上付き文字のコードの取り出しがわからなく str.codePointAt(1).toString(16))じゃないのかと思ったのですが違うみたいで とりあえず「^」を使った場合として x^3(x - 5) ^2 / 27 var x = 6; var str = 'x^3(x - 5) ^2 / 27'; str = str.replace(/x/g, x); str = str.replace(/\^/g, '**'); str = str.replace(/(\d)\(/g, "$1*("); //これは単純に(の前に*を入れている var result = Function('return (' + str + ');')(); console.log(result); 単純に「(」の前に「*」を入れているだけですので、実際は「*」を必要なところに追加する方法が必要だと思います。 https://ericsmekens.github.io/jsep/ ↑なんかこれでできるみたいですがよくわかりません。 BingAIに聞いたら以下の結果が出ましたが正しいかどうかは分かりません。 // JSEP.JSをインポート const jsep = require('jsep'); // 式をASTに変換 const ast = jsep('2x(3-4)b+3'); // ASTを走査して乗算演算子を挿入する関数 function insertMultiplication(node) { // ノードが識別子かリテラルなら何もしない if (node.type === 'Identifier' || node.type === 'Literal') { return node; } // ノードが二項演算子なら左右のオペランドに対して再帰的に処理 if (node.type === 'BinaryExpression') { node.left = insertMultiplication(node.left); node.right = insertMultiplication(node.right); // 左右のオペランドが識別子かリテラルなら乗算演算子に変更 if ((node.left.type === 'Identifier' || node.left.type === 'Literal') && (node.right.type === 'Identifier' || node.right.type === 'Literal')) { node.operator = '*'; } return node; } // ノードが括弧式なら中身に対して再帰的に処理 if (node.type === 'Compound') { node.body = node.body.map(insertMultiplication); return node; } } // ASTに乗算演算子を挿入 insertMultiplication(ast); // ASTを式に戻す関数 function astToExpression(node) { // ノードが識別子ならその名前を返す if (node.type === 'Identifier') { return node.name; } // ノードがリテラルならその値を返す if (node.type === 'Literal') { return node.value; } // ノードが二項演算子なら左右のオペランドと演算子を結合して返す if (node.type === 'BinaryExpression') { return `${astToExpression(node.left)} ${node.operator} ${astToExpression(node.right)}`; } // ノードが括弧式なら中身を結合して返す if (node.type === 'Compound') { return `(${node.body.map(astToExpression).join('')})`; } } // ASTから式を生成 const expression = astToExpression(ast); // 結果を表示 console.log(expression); // => "2 * x * (3 - 4) * b + 3"

retorofan
質問者

お礼

ご回答ありがとうございます。 かなり複雑になるようですね。

すると、全ての回答が全文表示されます。
回答No.6

FirefoxではなくてEdgeを使ってもまだ文字が化けるな。 OKWAVEでは珍しい。 □部分は何なのだろう?

retorofan
質問者

お礼

ご回答ありがとうございます。

すると、全ての回答が全文表示されます。
回答No.5

JavaScriptでかあ。JavaScriptはファイル操作と文字列操作をできそうなので、可能かどうかを言えばできる。 ただ、項を計算する種類の数だけその処理をするスクリプトが必要となり、かなり手間がかかる。x³(x-5)² / 27だけでも、1項のべき数、2項のべき数、掛け算、足し算である。 1回、1種類の計算処理と、再帰的に呼ぶところを作ってしまえば、あとはそのコピーとわずかな変更だから、それまでよりは楽そうだけど、楽と言っても大変だろう。 っと、ここで文字列数式のまとめにWolfram Mathematicaを使えそうな気がしてきた。向こうのサーバーがリクエストの頻度や回数に応えれば、だけど。

retorofan
質問者

お礼

ご回答ありがとうございます。 上付き文字の箇所が「3」としたら var i = 1; var y = 1; while(i<=3){ y = □□□□□; } こんな感じでできそうなのですが・・・

すると、全ての回答が全文表示されます。
  • _kappe_
  • ベストアンサー率68% (1606/2337)
回答No.4

> どこが自動変換になっていますか? すみません。乗算記号が省略されていてべき乗を上付き文字で表した文字列(そのままでは実行できない)を与えて、それをJavascriptで実行できる式に自動で変換したいということですか。 受け付ける式の複雑さをどこまで許すか次第ですが、そのような変換を行うプログラムは真面目にやると字句解析・構文解析の処理などが必要で、数百行以上のコードになりそうです。ここの回答欄に書ける規模ではないと思います。 頭のいい人なら簡潔な方法を思い付くかもしれませんが。

retorofan
質問者

お礼

そうです。

すると、全ての回答が全文表示されます。
回答No.3

ソースコード中の数式の項をxのn乗に関してまとめて、プログラマが見やすい形式(コンパイルできなくても見やすければよい?)にしたいのだと私は予想したんだけど、Javaを使って?Javaのソースコードがターゲット? いずれにしろ数式を解析してまとめるプログラムまたはsedか何かのスクリプトを作るのは面倒だなあ。エクセルにそんなのがあれば良いのだけど。 参考 > pythonで数式の構文解析をしてみた https://qiita.com/thtitech/items/91e2456c989ca969850d 置き換えの個数によっては手作業の方が早い(テキストファイル中の数式置き換えプログラムを作る方が大変)場合もある。 やるならすでにあるものを活用したい。例えばmaximaをOSのコマンドラインから引数を付けて実行、数式をまとめるのを活用とか。 (これは例ね。まずmaximaで出来るかどうかを調べなくちゃいけない。)

retorofan
質問者

お礼

ご回答ありがとうございます。 Javaではなくて JavaScriptで何とかなりませんか?

すると、全ての回答が全文表示されます。
  • _kappe_
  • ベストアンサー率68% (1606/2337)
回答No.2

Javascriptではべき乗をMath.pow()または**で書けます。ループを使って書く必要はありません。 質問中の式であれば var y = Math.pow(x, 3) * Math.pow(x-5, 2) / 27; または var y = x ** 3 * (x-5) ** 2 / 27; のようになります。

retorofan
質問者

お礼

ご回答ありがとうございます。 どこが自動変換になっていますか?

すると、全ての回答が全文表示されます。
回答No.1

肝心の所をブラウザが表示できていない。 そこは何だったのだろう?

retorofan
質問者

お礼

ご回答ありがとうございます。

すると、全ての回答が全文表示されます。

関連するQ&A