質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.33%

  • JavaScript

    17554questions

    JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

  • HTML

    9596questions

    HTMLとは、ウェブ上の文書を記述・作成するためのマークアップ言語のことです。文章の中に記述することで、文書の論理構造などを設定することができます。ハイパーリンクを設定できるハイパーテキストであり、画像・リスト・表などのデータファイルをリンクする情報に結びつけて情報を整理します。現在あるネットワーク上のほとんどのウェブページはHTMLで作成されています。

JavaScriptで取得した式を計算したい(四則演算のみ)

解決済

回答 4

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 1,021

ko20vonobird

score 41

前提・実現したいこと

HTMLのフォームから「式」を取得し、四則演算記号を判別して演算の順番通りに計算をこなしていくということを実現したいです。
仕組みとしては、四則演算子を一つずつ潰していく感じになります。今対応させるのは自然数のみです。
最終的に結果が全て計算されたものになるようなプログラムを目指しています。

発生している問題・エラーメッセージ

乗除計算では値が不自然なものに、和と差の計算では結果に"NaN"が含まれかつ式も右にそのまま出てきます。
三項以上の掛け算でNaNが出現します。

該当のソースコード

function keisan() { //a
    /*try{*/
    var chk1 = 0
    var str = document.siki.mainsiki.value;
    var strlong = str.length;
    for (var cnt = 0; cnt < 10; cnt++) { //b
        if (str.indexOf(cnt, 0) != 0) { //c
            chk1++
        } //c
    } //b
    if (chk1 > 9) { //d
        alert("最初の文字は数字にしてください");
        return;
    } //d
    var siki = str;
    var sikilong = siki.length;
    var sisoku = new Array();
    sisoku[0] = '+';
    sisoku[1] = '-';
    sisoku[2] = '*';
    sisoku[3] = '/';
    var sisokunum = 0;
    for (var cntstrnum = 0; cntstrnum < sikilong; cntstrnum++) { //e
        var chk = siki.charAt(cntstrnum);
        for (var cnta = 0; cnta < 4; cnta++) { //f
            if (chk == sisoku[cnta]) { //g
                sisokunum = sisokunum + 1;
            } //g
        } //f
    } //e
    if (sisokunum == 0) { //h
        alert("答え:" + siki);
        return;
    } //h
    //×÷の計算
    var nisokukw = 0;
    for (var cntnuma = 0; cntnuma < sikilong; cntnuma++) { //1
        var chk = siki.charAt(cntnuma);
        for (var cntb = 2; cntb < 4; cntb++) { //2
            if (chk == sisoku[cntb]) { //3
                nisokukw = nisokukw + 1;
            } //3
        } //2
    } //1
    var kakerupo = -1;
    var warupo = -1;
    for (var cntmaina = 0; cntmaina <= nisokukw; cntmaina++) { //4
        for (var cntc = 2; cntc < 4; cntc++) { //5
            if (siki.indexOf(sisoku[cntc]) != -1) { //6
                if (cntc == 2) { //7
                    kakerupo = siki.indexOf(sisoku[cntc]);
                } else if (cntc == 3) { //7
                    warupo = siki.indexOf(sisoku[cntc]);
                } //7
            } //6
        } //5
        if (kakerupo == -1 && warupo == -1) {
            break;
        }
        if (kakerupo != -1 && warupo != -1) { //8
            if (kakerupo > warupo) { //9
                var levelrl = kakerupo;
            } else { //9
                var levelrl = warupo;
            } //9
        } else if (kakerupo != -1) { //8
            var levelrl = kakerupo;
        } else if (warupo != -1) { //8
            var levelrl = warupo;
        } //8
        var levelll = -1;
        for (var cntd = levelrl - 1; cntd >= 0; cntd--) { //i
            if (levelll != -1) { //j
                break;
            } //j
            for (var cntnumb = 0; cntnumb < 4; cntnumb++) { //k
                if (siki.charAt(cntd) == sisoku[cntnumb]) { //l
                    var levelll = cntd;
                    break;
                } //l
                if (levelll != -1) { //m
                    break;
                } //m
            } //k
        } //i
        if (levelll == -1) { //n
            levelll = 0;
        } //n
        a = siki.substring(levelll, levelrl - 1);
        sikipa = siki.substring(0, levelll);
        var levellr = levelrl;
        var levelrr = -1;
        for (var cnte = levellr + 1; cnte < sikilong; cnte++) { //o
            for (var cntnumc = 0; cntnumc < 4; cntnumc++) { //p
                if (siki.charAt(cnte) == sisoku[cntnumc]) { //q
                    levelrr = siki.charAt(cnte);
                    break;
                } //q
                if (levelrr != -1) { //r
                    break;
                } //r
            } //p
            if (levelrr != -1) { ///u
                break;
            } ///u
        } //o
        if (levelrr == -1) { //s
            levelrr = sikilong;
        } //s
        b = siki.substring(levellr + 1, levelrr);
        sikipb = siki.substring(levelrr, sikilong - 1);
        if (levelrr == sikilong - 1){
            sikipb = "";
        }
        if (siki.charAt(levelrl) == sisoku[2]) { //t
            en = a * b;
        } else if (siki.charAt(levelrl) == sisoku[3]) { //t
            en = a / b;
        } //t
        if (levelll == 0){
            sikipa = "";
        }
        siki = sikipa + en + sikipb;
        sikilong = siki.length;
    } //4
    //+-の計算
    var nisokuth = 0;
    for (var cntf = 0; cntf <= sikilong; cntf++) {
        for (var cntnumd = 0; cntnumd < 4; cntnumd++) {
            if (sisoku[cntnumd] == siki.charAt(cntf)) {
                nisokuth++;
            }
        }
    }
    for (var cntmainb = 0; cntmainb <= nisokuth; cntmainb++) { //1
        var middle = -1;
        for (var cntg = 0; cntg < sikilong; cntg++) { //2
            for (var cntnume = 0; cntnume < 2; cntnume++) { //3
                if (sisoku[cntnume] == siki.charAt(cntg)) { //4
                    var middle = cntg;
                    break;
                } //4
                if (middle != -1) { //5
                    break;
                } //5
            } //3
            if (middle == -1) {
                break;
            }
            var lrright = -1;
            var llleft = 0;
            var llright = middle - 1;
            var lrleft = middle + 1;
            for (var cntaa = lrleft; cntaa < sikilong - lrleft + 1; cntaa++) {
                for (var cntnumaa = 0; cntnumaa < 2; cntnumaa++) {
                    if (sisoku[cntnumaa] == siki.charAt(cntaa)) {
                        lrright = cntaa - 1;
                        break;
                    }
                }
                if (lrright == -1) {
                    lrlight = sikilong;
                }
            }
            var a = siki.substring(llleft, llright);
            var b = siki.substring(lrleft, lrright);
            if (siki.charAt(middle) == sisoku[0]) {
                en = a + b;
            } else if (siki.charAt(middle) == sisoku[1]) {
                en = a - b;
            }
            var sikipb = substring(lrright, sikilong);
            siki = en + sikipb;
        } //2
        if (middle == -1) {
            alert("答え:" + siki);
            return;
        }
    } //1
    /*}catch(e){
    alert("式が不適合もしくはエラーです。");
    return;
    }
    finally{
    return;
    }*/
} //a

試したこと

コードを見たらわかるかと思いますが、括弧がちゃんと対応しているか英数字をふって確かめたりしました。
デバッグも粗方行いました。

補足情報(言語/FW/ツール等のバージョンなど)

特になし

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • matobaa

    2017/01/05 23:44

    3か所ほど、if文中の比較すべきところで代入しているように見えるところがありますが意図通りでしょうか? ところでhttp://jsbeautifier.org/ に貼り付けて Beautifierボタンを押すときれいに整形してくれますよ。

    キャンセル

  • ko20vonobird

    2017/01/06 00:07

    まず、整形できるサイトを教えてくださりありがとうございます。ところで、現在確認中ですが、それが条件式の中であれば私のミスです。そうでなければ意図通りのはずです。

    キャンセル

  • kei344

    2017/01/06 00:14

    「最初の文字は数字に」とありますが、「-1」も数字です。これは無視するということで問題ないですか?

    キャンセル

  • ko20vonobird

    2017/01/06 00:23

    kei344さん、書くのを忘れていました、今のバージョンは自然数で四則演算をする場合のみ対応するという設定で設計しております。なので、-の場合は今はメモにしてあるtryでエラーとして検出しようと思っております。

    キャンセル

回答 4

+4

参考までに、似た要件のコードを書いたことがあります。

質問文に書かれたコードは全体的に見通しが悪いので、和算/減算/積算/除算をそれぞれ関数化してコードを分けて切り分けすると問題点がはっきりして良いと思います。
細かな最適化は後でも出来ます。

Re: ko20vonobird さん

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/01/06 09:34

    think49さん、回答ありがとうございます。四則に分けて計算をさせるのが良いことは存じております。一方で、私の個人的な課題としまして一つの関数で全ての計算ができるように目指しております。なので、今回は大変恐縮で、かつコードとしても汚いのは承知の上で、進められたらと思います。

    キャンセル

  • 2017/01/06 10:23

    > 私の個人的な課題としまして一つの関数で全ての計算ができるように目指しております

    なんでそんなことを?

    キャンセル

  • 2017/01/06 10:30

    ozwkさん、質問ありがとうございます。質問にの題名の横にある通り私は初心者です、故に、スマートなやり方は私にとっては少々知識を更に要求されると思うからです。また、今まで他の言語を勉強してきたときもまずは粗削りなコードを書くことでまずはおおまかな流れをつかもうと試みています。要は、分割するやり方は書くのに複雑ではないかと思慮し、まずは汚くても流れがつかめる方をしようと思ったのです。

    キャンセル

  • 2017/01/06 10:37

    >ko20vonobirdさん
    回答ではないので恐縮ですが、今回のバグについては言語の仕様云々というよりアルゴリズムの間違いによるバグに見えます。
    勉強のためにあえてこうしているというのであればご自身でデバッグしていったほうがいいと思いますよ。
    数分デバッグしただけですが時間をかけて処理を追っていけば十分修正できる内容だと感じました。

    キャンセル

  • 2017/01/06 10:47

    koronatailさん、ありがとうございます、なるほど、直せるレベルのものでしたか。私初心者であるが故ついつい自分では直せないかと思い込んでいました。しかしおかげで修正できるものだとわかりました。あとはできる限り自分でデバッグして修正していこうと思います、ありがとうございます。

    キャンセル

+3

全体をスクロールする程度に読みましたが、頭に入ってきにくいというのが感想です。
相当な熟練者でもない限り、このコードを一読して指摘・修正するのは難しいのではないでしょうか。
質問者の方は初心者ということですが、そのレベルと逸脱した
上級者にしかわからないコード(上級者向けのコードとは違います)を書いているということになります。
誰でも(数か月後の自分も)読めるコードを書くのが、プログラミングには必要です。

具体的には
●変数の説明をコメントに記述する(説明がいらないような命名が理想です)
例)nisokukw・・・*と/の数
●行う処理の説明をコメントしておく(これも説明がいらないようなfunction名などで処理を分けるのが理想です)

さて、具体的なコードは書きませんが、私なら以下のフローで書くと思います。()は使わないという前提です。

1 フォームの文字列を加算、減算で分解
"5-4/6-8+9/7*2+5-7*8"

[ ["+" , "5" ] , ["-" , "4/6"] , ["-" , "8"] , ["+" , "9/7*2"] , ["+" , "5"] , ["-" , "7*8"] ]
とする。
2 各配列の第二要素をそれぞれ計算。
3 各配列の第一要素にのっとって、第二要素を集計

ご参考になれば、幸甚です。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/01/06 15:31

    なるほど、今の状態は雑に組み上げたハウスのような感じなのですね。分かりやすく整えられるように頑張ります。
    そのやり方は思いつきませんでした、参考にさせていただきます、ありがとうございます。

    キャンセル

checkベストアンサー

+1

乱暴ですが要件を満たすだけならeval関数で計算できるんじゃないでしょうか。

function keisan(){
    var ans = eval("10*10*30");
    alert(ans);
}


evalを使うくらいならthink49さんが製作した関数を使うほうがよさそうですが。
コード自体はsubstringの文字の切り出し位置がずれて計算が正しく行えていないように感じましたが、このレベルのバグになると作った本人がデバッグで地道に修正していくのが一番早いじゃないでしょうか。
どうしてもこの方式を大きく変えたくないというのであれば、think49さんのおっしゃるとおり一旦和算/減算/積算/除算それぞれの計算を行う関数に分割してデバッグしたほうがいいような気がします。
問題点が分かってからくっつけてもいいわけですし。
4つの計算関数を作ったうえで、文字列式の書式チェックを行って必要な関数を呼び出す四則演算関数を別に作るとかもありかもしれません。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/01/06 10:44

    koronatailさん、回答ありがとうございます。evalは初めて知ったのですが、あらゆる文字列を整形するような機能を持つということで合っていますでしょうか?
    確かに、切り出し位置がずれているところが非常に多く、私のミスで大変申し訳ないです。
    もうしばらく待ってみて、回答が来なければ、質問を終了することも検討します(未解決ですが)。
    ところで、式の答えでNaNがでることがあるのですが、これの原因として考えられるものは何でしょうか?

    キャンセル

  • 2017/01/06 11:35

    >ko20vonobirdさん
    eval関数は「与えられた文字列をJavascriptのコードとして評価する」関数です。
    たとえば以下のような式を実行すると「ハロー」という内容のアラートが表示されます。
     eval("alert('ハロー')");
    テキストボックスの値をそのままevalに突っ込んだりすると何が起こるかわからないので利用方法はよく考える必要があります。PHP等のevalに比べると危険性は低いですが、それでも単に四則演算をしたいだけというのであればthink49さんの関数を使ったほうがいいと思います。
    答えでNaNが出ているのは、substringの文字列切り出しの位置がずれてしまい「"10" × "10*"」のような計算を行ってしまっているのが原因のようですね。

    キャンセル

  • 2017/01/06 15:29

    >koronatailさん
    なるほど、万能というわけではないのですね。
    そういうことが起きていたのですか、理解しました、ありがとうございます。

    キャンセル

+1

"javascript expression eval" で google 検索すると 数式の評価を javascript で行うことに関する情報をえられます。

たとえば

数式の評価の実装は、コンパイラ、インタープリターをつくる際も入門的な知識が必要です。

他にもこんなページがみつかります。

これらのコードを研究してみてから、質問文のコードをみなおすとよいと思います。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.33%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る

  • JavaScript

    17554questions

    JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

  • HTML

    9596questions

    HTMLとは、ウェブ上の文書を記述・作成するためのマークアップ言語のことです。文章の中に記述することで、文書の論理構造などを設定することができます。ハイパーリンクを設定できるハイパーテキストであり、画像・リスト・表などのデータファイルをリンクする情報に結びつけて情報を整理します。現在あるネットワーク上のほとんどのウェブページはHTMLで作成されています。