こんにちはゲストさん。会員登録(無料)して質問・回答してみよう!

解決済みの質問

evalを使うinputがある場合も安全に運用する

https://okwave.jp/qa/q9368497.html
のつづき

evalを使うinputがある場合も安全に運用するために、エスケープしたいのですが、
下記のご回答で問題ないでしょうか?
>>>
「四則演算子、数字、括弧」以外は削除されます。<br>
また式として成立しない文字列は計算できません。<br>
<input type="text" name="gakunen" value="" onKeyPress="Calculator(this.value, event.keyCode)">

<script type="text/javascript">
<!--
function Calculator(a, kcode){
var r;
if (!(13==kcode)){return;}
// ↑「13:Enterキー」でない場合は「return」
r = a;
r = r.replace(/[ ]*([\-\/\*\+])[ \-\/\*\+]*/g, '$1');
r = r.replace(/^([ ]*[\/\*\+][ \-\/\*\+]*)/g, '');
r = r.replace(/([^0-9\.\-\/\*\+\(\) ]+)/g, ' ');
r = r.replace(/([ ]+)/g, ' ');
try{
alert(r+' = '+eval(r));
}catch(ex){
alert(ex.message+' : '+r);
}
}
// -->
</script>





またエスケープの表記位置はevalを実行する前であればどこでも良いのでしょうか?

投稿日時 - 2017-09-02 09:59:10

QNo.9369932

困ってます

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

>!"#$%&',:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
>をInputに入れてアラートの処理が実行されるか確かめてみます

「catch内が実行されるか(アラートの処理が実行されるか)」ではなく

>r = r.replace(/([^0-9\.\-\/\*\+\(\) ]+)/g, ' ');
>r = r.replace(/([\*\/])[ \+\-\*\/]*([\+\-])[ ]*([0-9\.\(]+)/g, '$1$2$3');
>r = r.replace(/[\+\-][ \+\-\*\/]*([\+\-])[ ]*([0-9\.\(]+)/g, '$1$2');
>r = r.replace(/(^|\()[ \+\-\*\/]*([\+\-])/g, '$1$2');
>r = r.replace(/(^|\()[ \+\-\*\/]*[\*\/]/g, '$1');
>r = r.replace(/([\+\-\*\/])[ \+\-\*\/]*[\*\/][ ]*([0-9\.\(]+)/g, '$1$2');
>r = r.replace(/([ ]+)/g, ' ');

↑この「r」変数の値が''(ヌル文字)(文字が何も無い文字列)になるか、実際の「r」変数の値を表示してみて下さい。

投稿日時 - 2017-09-15 09:16:30

このQ&Aは役に立ちましたか?

0人が「このQ&Aが役に立った」と投票しています

回答(22)

ANo.21

>アラートが実行できなかったら他の関数は試さなくても問題ないとわかるということですかね。

(何か実行できるかと言うより)英文字、記号などが除去されていれば良い訳です。

!"#$%&',:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~

↑ざっくりと言うと、これを入力して下記の「r」変数の値に何も返って来なければ基本的にOKです。

>r = r.replace(/([^0-9\.\-\/\*\+\(\) ]+)/g, ' ');
>r = r.replace(/([\*\/])[ \+\-\*\/]*([\+\-])[ ]*([0-9\.\(]+)/g, '$1$2$3');
>r = r.replace(/[\+\-][ \+\-\*\/]*([\+\-])[ ]*([0-9\.\(]+)/g, '$1$2');
>r = r.replace(/(^|\()[ \+\-\*\/]*([\+\-])/g, '$1$2');
>r = r.replace(/(^|\()[ \+\-\*\/]*[\*\/]/g, '$1');
>r = r.replace(/([\+\-\*\/])[ \+\-\*\/]*[\*\/][ ]*([0-9\.\(]+)/g, '$1$2');
>r = r.replace(/([ ]+)/g, ' ');

投稿日時 - 2017-09-15 02:43:30

お礼

ありがとうございます。

!"#$%&',:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~


をInputに入れてアラートの処理が実行されるか確かめてみます

投稿日時 - 2017-09-15 07:35:06

ANo.20

>これでセキュアに使えるようになったと考えてよろしいでしょうか?

>r = r.replace(/([^0-9\.\-\/\*\+\(\) ]+)/g, ' ');

↑これで「四則演算子、数字、括弧」以外を除去してます。
これで基本的に関数類は実行できません。
ここは簡単なのでバグの入り込む余地はありません。

>r = r.replace(/([\*\/])[ \+\-\*\/]*([\+\-])[ ]*([0-9\.\(]+)/g, '$1$2$3');
>r = r.replace(/[\+\-][ \+\-\*\/]*([\+\-])[ ]*([0-9\.\(]+)/g, '$1$2');
>r = r.replace(/(^|\()[ \+\-\*\/]*([\+\-])/g, '$1$2');
>r = r.replace(/(^|\()[ \+\-\*\/]*[\*\/]/g, '$1');
>r = r.replace(/([\+\-\*\/])[ \+\-\*\/]*[\*\/][ ]*([0-9\.\(]+)/g, '$1$2');

↑これで(四則演算にならない)不正な「四則演算子」を除去してます。
ここはバグの入り込む余地がありますが、それほど複雑でもないので これで問題ないと思われます。
もしバグがあっても不正な「四則演算子」が残るだけなので、基本的に関数類は実行できません。

よって、(ハッキングでもされない限り)安全に「eval」を実行できるでしょう。

投稿日時 - 2017-09-14 21:51:33

補足

アラートが実行できなかったら他の関数は試さなくても問題ないとわかるということですかね。

投稿日時 - 2017-09-14 22:49:39

ANo.19

>>オブジェクトでも関数でもありません。
>>ざっくり言うと「if」文的な文です、「try」ブロック内で実行文がエラーになると例外が発生し、「catch」ブロック内が実行されます。

>whileなどと同じ構文の一種なのですね。
>tryはうまくいかずエラーが出た場合つまり、偽ならもう一つの処理を行うというものなのですかね。

ループではないので、「if」文的な文と考えて下さい、「try」ブロック内で実行文がエラーになると例外が発生し、「catch」ブロック内が実行されます。

>><input type="text" name="gakunen" value="" onKeyPress="Calculator(this.value, event.keyCode)">

>イベントリスナーを使うのでこれが何を示しているかいまいちわからないのですが、
>何かキーボードを押したときに自作のCalculator
>関数が実行されるという事でしょうか?
>つまり何かキーボードを操作したときに毎回
>>r = a;
>>r = r.replace(/([^0-9\.\-\/\*\+\(\) ]+)/g, ' ');
>>r = r.replace(/([\*\/])[ \+\-\*\/]*([\+\-])[ ]*([0-9\.\(]+)/g, '$1$2$3');
>>r = r.replace(/[\+\-][ \+\-\*\/]*([\+\-])[ ]*([0-9\.\(]+)/g, '$1$2');
>>r = r.replace(/(^|\()[ \+\-\*\/]*([\+\-])/g, '$1$2');
>>r = r.replace(/(^|\()[ \+\-\*\/]*[\*\/]/g, '$1');
>>r = r.replace(/([\+\-\*\/])[ \+\-\*\/]*[\*\/][ ]*([0-9\.\(]+)/g, '$1$2');
>>r = r.replace(/([ ]+)/g, ' ');
>が実行されて、記載した文字が上記でエスケープされるという事でしょうか?

下記で「Enterキー」でない場合は「return」してます。

if (!(13==kcode)){return;}
// ↑「13:Enterキー」でない場合は「return」

>エラー処理というものはエラーが起きてうまく計算できなかった時に出るalert()を作ればよさそうですね。

それ以外に「result = '';」とか代入しておかないと「result」変数が「undefined」になり、「Calculator」関数の帰り値が「undefined」になると思います。

>エンターを押した所、undefunedというアラートが出ました。

何か変な事をしてませんか?、例えば「test000.html」と言う新規ファイルを作って下記をコピペして下さい。


「四則演算子、数字、括弧」以外は除去されます。<br>
また式として成立しない文字列は計算できません。<br>
<input type="text" name="gakunen" value="" onKeyPress="Calculator(this.value, event.keyCode)">

<script type="text/javascript">
<!--
function Calculator(a, kcode){
var r;
if (!(13==kcode)){return;}
// ↑「13:Enterキー」でない場合は「return」
r = a;
r = r.replace(/([^0-9\.\-\/\*\+\(\) ]+)/g, ' ');
r = r.replace(/([\*\/])[ \+\-\*\/]*([\+\-])[ ]*([0-9\.\(]+)/g, '$1$2$3');
r = r.replace(/[\+\-][ \+\-\*\/]*([\+\-])[ ]*([0-9\.\(]+)/g, '$1$2');
r = r.replace(/(^|\()[ \+\-\*\/]*([\+\-])/g, '$1$2');
r = r.replace(/(^|\()[ \+\-\*\/]*[\*\/]/g, '$1');
r = r.replace(/([\+\-\*\/])[ \+\-\*\/]*[\*\/][ ]*([0-9\.\(]+)/g, '$1$2');
r = r.replace(/([ ]+)/g, ' ');
try{
alert(r+' = '+eval(r)); // ←ここで「eval」を使ってます。
}catch(ex){
alert(ex.message+' : '+r);
}
}
// -->
</script>

投稿日時 - 2017-09-14 19:51:40

補足

確認しました
r = r.replace(/([^0-9\.\-\/\*\+\(\) ]+)/g, ' ');
の前までは文字列があり、
これ以降に空になりました。

ソースのご質問は別質問にしますので、よろしければ、お付き合いお願いします。

投稿日時 - 2017-09-15 09:43:19

お礼

ありがとうございます。

おかげさまでalert();をいれるとエラー時のアラートが表記され、
計算式を入れるとちゃんと計算結果が出るようになりました。

これでセキュアに使えるようになったと考えてよろしいでしょうか?

他にもこんな関数を入れて調べたほうがいいというものがあれば教えていただければ幸いです。

投稿日時 - 2017-09-14 21:12:01

ANo.18

エラー処理に何か書いた方が良いです、下記は一例です、自分に合ったエラー処理を記述して下さい。

>}catch(ex){
>// エラー処理
>}

}catch(ex){
// エラー処理
result = '';
}

投稿日時 - 2017-09-14 01:22:08

お礼

これエラー処理というものはエラーが起きてうまく計算できなかった時に出るalert()を作ればよさそうですね。

結果計算がうまくいかなかった時に処理する部分なのでしょうから、
閲覧者さんにそれがわかるメッセージがあればいいのですね。

投稿日時 - 2017-09-14 17:58:30

ANo.17

>イベントリスナーを使うのでこれが何を示しているかいまいちわからないのですが

実際にコピペして動作させててみれば分かると思います。

>何かキーボードを押したときに自作のCalculator
>関数が実行されるという事でしょうか?

Enterキーで実行されます。

>私の場合、freeBtnを押したときに計算が実行されるので、freeBtnを押したときに

大体、下記のようになるハズです。

var freeBtn = document.getElementById('freeBtn');
freeBtn.addEventListener('click', function() {
var userInput = document.getElementById('freeUserInput').value;
var freeResult = Calculator(userInput);
freeResult = round(freeResult);
if (!(userInput === '')) {
} else {
}
});

function Calculator(a){
var r, result;
r = a;
r = r.replace(/([^0-9\.\-\/\*\+\(\) ]+)/g, ' ');
r = r.replace(/([\*\/])[ \+\-\*\/]*([\+\-])[ ]*([0-9\.\(]+)/g, '$1$2$3');
r = r.replace(/[\+\-][ \+\-\*\/]*([\+\-])[ ]*([0-9\.\(]+)/g, '$1$2');
r = r.replace(/(^|\()[ \+\-\*\/]*([\+\-])/g, '$1$2');
r = r.replace(/(^|\()[ \+\-\*\/]*[\*\/]/g, '$1');
r = r.replace(/([\+\-\*\/])[ \+\-\*\/]*[\*\/][ ]*([0-9\.\(]+)/g, '$1$2');
r = r.replace(/([ ]+)/g, ' ');
try{
result = eval(r);
}
}catch(ex){
// エラー処理
}
return result;
}

投稿日時 - 2017-09-13 22:16:26

ANo.16

>回答No.15 amanojaku1

例えばinputエレメントに「2*3」と入力したらEnterキーを入力してみて下さい。

投稿日時 - 2017-09-13 18:17:40

ANo.15

>回答No.14 amanojaku1

>if (!(13==kcode)){return;}
>// ↑「13:Enterキー」でない場合は「return」

Enterキーで「Calculator」関数内の それ以降が実行されます。

投稿日時 - 2017-09-13 18:10:42

お礼

エンターを押した所、undefunedというアラートが出ました。

if (!(13==kcode))の部分が恐らくエンターを押した場合に内部の処理を実行という意味なのですね。
つまり13がキーボードの数値で他のキーを押しても反応しないようにしているのですね。


これを私の場合はエンターを押したときにエスケープして、私の計算処理をするから、ボタンを押したときにこの二つを行うと変更すれば終了という事とでよろしいでしょうか?

投稿日時 - 2017-09-14 11:59:07

ANo.14

>>try{
>>alert(r+' = '+eval(r)); // ←ここで「eval」を使ってます。
>>}catch(ex){
>>alert(ex.message+' : '+r);
>>}

>これは、オブジェクトですか?
>tryとはなんでしょうか?
>関数にも似ていますが、この形は初めて見ました。

オブジェクトでも関数でもありません。
ざっくり言うと「if」文的な文です、「try」ブロック内で実行文がエラーになると例外が発生し、「catch」ブロック内が実行されます。


>結論としては下記でよいのですね
>function Calculator(a, kcode){
>var r;
>if (!(13==kcode)){return;}
>// ↑「13:Enterキー」でない場合は「return」
>r = a;
>r = r.replace(/([^0-9\.\-\/\*\+\(\) ]+)/g, ' ');
>r = r.replace(/([\*\/])[ \+\-\*\/]*([\+\-])[ ]*([0-9\.\(]+)/g, '$1$2$3');
>r = r.replace(/[\+\-][ \+\-\*\/]*([\+\-])[ ]*([0-9\.\(]+)/g, '$1$2');
>r = r.replace(/(^|\()[ \+\-\*\/]*([\+\-])/g, '$1$2');
>r = r.replace(/(^|\()[ \+\-\*\/]*[\*\/]/g, '$1');
>r = r.replace(/([\+\-\*\/])[ \+\-\*\/]*[\*\/][ ]*([0-9\.\(]+)/g, '$1$2');
>r = r.replace(/([ ]+)/g, ' ');
>
>try{
>var freeBtn = document.getElementById('freeBtn');
>freeBtn.addEventListener('click', function() {
>var userInput = document.getElementById('freeUserInput').value;
>var freeResult = eval(userInput);
>freeResult = round(freeResult);
>if (!(userInput === '')) {
>} else {
>}
>});
>}

「input」タグから「onKeyPress」イベントで「Calculator(this.value, event.keyCode)」を呼ぶように作ってあるのですが?、実際に下記を実行してみましたか?



「四則演算子、数字、括弧」以外は除去されます。<br>
また式として成立しない文字列は計算できません。<br>
<input type="text" name="gakunen" value="" onKeyPress="Calculator(this.value, event.keyCode)">

<script type="text/javascript">
<!--
function Calculator(a, kcode){
var r;
if (!(13==kcode)){return;}
// ↑「13:Enterキー」でない場合は「return」
r = a;
r = r.replace(/([^0-9\.\-\/\*\+\(\) ]+)/g, ' ');
r = r.replace(/([\*\/])[ \+\-\*\/]*([\+\-])[ ]*([0-9\.\(]+)/g, '$1$2$3');
r = r.replace(/[\+\-][ \+\-\*\/]*([\+\-])[ ]*([0-9\.\(]+)/g, '$1$2');
r = r.replace(/(^|\()[ \+\-\*\/]*([\+\-])/g, '$1$2');
r = r.replace(/(^|\()[ \+\-\*\/]*[\*\/]/g, '$1');
r = r.replace(/([\+\-\*\/])[ \+\-\*\/]*[\*\/][ ]*([0-9\.\(]+)/g, '$1$2');
r = r.replace(/([ ]+)/g, ' ');
try{
alert(r+' = '+eval(r)); // ←ここで「eval」を使ってます。
}catch(ex){
alert(ex.message+' : '+r);
}
}
// -->
</script>

投稿日時 - 2017-09-13 17:58:25

お礼

>>>
オブジェクトでも関数でもありません。
ざっくり言うと「if」文的な文です、「try」ブロック内で実行文がエラーになると例外が発生し、「catch」ブロック内が実行されます。

whileなどと同じ構文の一種なのですね。
tryはうまくいかずエラーが出た場合つまり、偽ならもう一つの処理を行うというものなのですかね。




>>>
<input type="text" name="gakunen" value="" onKeyPress="Calculator(this.value, event.keyCode)">


イベントリスナーを使うのでこれが何を示しているかいまいちわからないのですが、
何かキーボードを押したときに自作のCalculator
関数が実行されるという事でしょうか?


つまり何かキーボードを操作したときに毎回
>r = a;
>r = r.replace(/([^0-9\.\-\/\*\+\(\) ]+)/g, ' ');
>r = r.replace(/([\*\/])[ \+\-\*\/]*([\+\-])[ ]*([0-9\.\(]+)/g, '$1$2$3');
>r = r.replace(/[\+\-][ \+\-\*\/]*([\+\-])[ ]*([0-9\.\(]+)/g, '$1$2');
>r = r.replace(/(^|\()[ \+\-\*\/]*([\+\-])/g, '$1$2');
>r = r.replace(/(^|\()[ \+\-\*\/]*[\*\/]/g, '$1');
>r = r.replace(/([\+\-\*\/])[ \+\-\*\/]*[\*\/][ ]*([0-9\.\(]+)/g, '$1$2');
>r = r.replace(/([ ]+)/g, ' ');
が実行されて、記載した文字が上記でエスケープされるという事でしょうか?

すると関係ないところに入力した場合も実行されてしまいますね。

私の場合、freeBtnを押したときに計算が実行されるので、freeBtnを押したときにだけ上記を実行し、
その下に
>var userInput = document.getElementById('freeUserInput').value;
>var freeResult = eval(userInput);
>freeResult = round(freeResult);
>if (!(userInput === '')) {
>} else {
>}
>});
が来ればエスケープされたものがevalに渡されると思うのですが、どうでしょうか?
evalに渡される前にevalに渡す入力文字だけを上記のエスケープをすればよいで素よね?

投稿日時 - 2017-09-13 21:17:30

ANo.13

>回答No.12 amanojaku1

>(「try」ブロック内に「eval」を記述した場合)式として成立してない文字列の場合に例外が発生し、「catch」ブロック内の処理が実行されます。

「try~catch」は「eval」以外でも使用できます、「try」ブロック内でエラーが発生すると、「catch」ブロック内の処理が実行されます。

投稿日時 - 2017-09-12 23:01:32

ANo.12

>ただこの記述をどこに記載したらいいのですか?evalを使う直前に記載したらいいのですか?

そうです、下記のサンプルを参照して下さい。
(下記のサンプルのように)必ず「try」ブロック内に「eval」を記述して下さい。
(「try」ブロック内に「eval」を記述した場合)式として成立してない文字列の場合に例外が発生し、「catch」ブロック内の処理が実行されます。
実際に式として成立してない文字列を入力してみれば「catch」ブロック内の処理が実行されているのが分かると思います(例として「1.2.3」、「1+」、「2(1」、「3(2)」など)。



「四則演算子、数字、括弧」以外は除去されます。<br>
また式として成立しない文字列は計算できません。<br>
<input type="text" name="gakunen" value="" onKeyPress="Calculator(this.value, event.keyCode)">

<script type="text/javascript">
<!--
function Calculator(a, kcode){
var r;
if (!(13==kcode)){return;}
// ↑「13:Enterキー」でない場合は「return」
r = a;
r = r.replace(/([^0-9\.\-\/\*\+\(\) ]+)/g, ' ');
r = r.replace(/([\*\/])[ \+\-\*\/]*([\+\-])[ ]*([0-9\.\(]+)/g, '$1$2$3');
r = r.replace(/[\+\-][ \+\-\*\/]*([\+\-])[ ]*([0-9\.\(]+)/g, '$1$2');
r = r.replace(/(^|\()[ \+\-\*\/]*([\+\-])/g, '$1$2');
r = r.replace(/(^|\()[ \+\-\*\/]*[\*\/]/g, '$1');
r = r.replace(/([\+\-\*\/])[ \+\-\*\/]*[\*\/][ ]*([0-9\.\(]+)/g, '$1$2');
r = r.replace(/([ ]+)/g, ' ');
try{
alert(r+' = '+eval(r)); // ←ここで「eval」を使ってます。
}catch(ex){
alert(ex.message+' : '+r);
}
}
// -->
</script>

投稿日時 - 2017-09-12 22:43:50

お礼

try{
alert(r+' = '+eval(r)); // ←ここで「eval」を使ってます。
}catch(ex){
alert(ex.message+' : '+r);
}


これは、オブジェクトですか?
tryとはなんでしょうか?
関数にも似ていますが、この形は初めて見ました。



結論としては下記でよいのですね
function Calculator(a, kcode){
var r;
if (!(13==kcode)){return;}
// ↑「13:Enterキー」でない場合は「return」
r = a;
r = r.replace(/([^0-9\.\-\/\*\+\(\) ]+)/g, ' ');
r = r.replace(/([\*\/])[ \+\-\*\/]*([\+\-])[ ]*([0-9\.\(]+)/g, '$1$2$3');
r = r.replace(/[\+\-][ \+\-\*\/]*([\+\-])[ ]*([0-9\.\(]+)/g, '$1$2');
r = r.replace(/(^|\()[ \+\-\*\/]*([\+\-])/g, '$1$2');
r = r.replace(/(^|\()[ \+\-\*\/]*[\*\/]/g, '$1');
r = r.replace(/([\+\-\*\/])[ \+\-\*\/]*[\*\/][ ]*([0-9\.\(]+)/g, '$1$2');
r = r.replace(/([ ]+)/g, ' ');

try{
var freeBtn = document.getElementById('freeBtn');
freeBtn.addEventListener('click', function() {
var userInput = document.getElementById('freeUserInput').value;
var freeResult = eval(userInput);
freeResult = round(freeResult);

if (!(userInput === '')) {

} else {

}
});
}

投稿日時 - 2017-09-13 11:34:05

ANo.11

>replaceというのは第一引数の文字列を第二引数の文字列に変換する関数のようですね。

正確に言うと正規表現で変換します。

>>r = r.replace(/([\*\/])[ \+\-\*\/]*([\+\-])[ ]*([0-9\.\(]+)/g, '$1$2$3');

>であれば*や+,-などを123に変更しているのですかね?

違います。
不正な「四則演算子」を除去してます。
例えば「*/+-123.456」は「*-123.456」に変換されます。

>r = r.replace(/(^|\()[ \+\-\*\/]*([\+\-])/g, '$1$2');

↑こちらは、例えば「(*/+-」は「(-」に変換されます。

正規表現は下記ページを参照して下さい。

正規表現 - JavaScript | MDN
https://developer.mozilla.org/ja/docs/Web/JavaScript/Guide/Regular_Expressions

投稿日時 - 2017-09-12 18:41:19

お礼

正規表現がわかっていないと理解するのが難しそうですが、
とりあえず危険な記載を安全な記載に変換しているのですね。

ただこの記述をどこに記載したらいいのですか?evalを使う直前に記載したらいいのですか?

投稿日時 - 2017-09-12 21:03:25

ANo.10

>回答No.9 amanojaku1

>>r = r.replace(/([\*\/])[ \+\-\*\/]*([\+\-])[ ]*([0-9\.\(]+)/g, '$1$2$3');
>>r = r.replace(/[\+\-][ \+\-\*\/]*([\+\-])[ ]*([0-9\.\(]+)/g, '$1$2');
>>r = r.replace(/(^|\()[ \+\-\*\/]*([\+\-])/g, '$1$2');
>>r = r.replace(/(^|\()[ \+\-\*\/]*[\*\/]/g, '$1');
>>r = r.replace(/([\+\-\*\/])[ \+\-\*\/]*[\*\/][ ]*([0-9\.\(]+)/g, '$1$2');

>↑これで(四則演にならない)不正な「四則演算子」を除去してます。
>ここはバグの入り込む余地がありますが、それほど複雑でもないので問題ないと思われます。

↑これで(四則演算にならない)不正な「四則演算子」を除去してます。
ここはバグの入り込む余地がありますが、それほど複雑でもないので これで問題ないと思われます。

投稿日時 - 2017-09-07 22:36:57

お礼

いつもお手伝いいただき大変ありがとうございます。

自分でも調べてみたところ
replaceというのは第一引数の文字列を第二引数の文字列に変換する関数のようですね。


>>>
>>r = r.replace(/([\*\/])[ \+\-\*\/]*([\+\-])[ ]*([0-9\.\(]+)/g, '$1$2$3');

であれば*や+,-などを123に変更しているのですかね?

>>>
var str = 文字列
str.replace(対象の文字, 置換する文字);
「文字列」の中から「対象の文字」を検索し、一致した文字を「置換する文字」に変換してくれるのが「replace()」の基本的な機能になります。

投稿日時 - 2017-09-11 15:39:07

ANo.9

>回答No.5 amanojaku1

>r = r.replace(/([^0-9\.\-\/\*\+\(\) ]+)/g, ' ');

↑これで「四則演算子、数字、括弧」以外を除去してます。
これで基本的に関数類は実行できません。
ここは簡単なのでバグの入り込む余地はありません。

>r = r.replace(/([\*\/])[ \+\-\*\/]*([\+\-])[ ]*([0-9\.\(]+)/g, '$1$2$3');
>r = r.replace(/[\+\-][ \+\-\*\/]*([\+\-])[ ]*([0-9\.\(]+)/g, '$1$2');
>r = r.replace(/(^|\()[ \+\-\*\/]*([\+\-])/g, '$1$2');
>r = r.replace(/(^|\()[ \+\-\*\/]*[\*\/]/g, '$1');
>r = r.replace(/([\+\-\*\/])[ \+\-\*\/]*[\*\/][ ]*([0-9\.\(]+)/g, '$1$2');

↑これで(四則演にならない)不正な「四則演算子」を除去してます。
ここはバグの入り込む余地がありますが、それほど複雑でもないので問題ないと思われます。
もしバグがあっても不正な「四則演算子」が残るだけなので、基本的に関数類は実行できません。

投稿日時 - 2017-09-07 22:33:17

ANo.8

#7

小数対応してなかったorz

でも単純な書き足し付け足しでいけそうだし
ほとんど答えがすでに別レスにあるし、
主さんに自分で頑張っていただきますか

投稿日時 - 2017-09-04 22:40:11

ANo.7

<input type="text" name="gakunen" value="" onKeyPress="Calculator(this.value, event.keyCode)">
<script type="text/javascript">
<!--
function Calculator(a, kcode){
var r,match;
try{
if (!(13==kcode)){return;}
r=a.replace(/\s/,'');
if(/[^0-9\+\-\*\/\(\)]/g.test(r)){throw '半角数字と()+-*/で入力してください';}
if(match=r.match(/(\([\+\*\/]|[\+\-\*\/]\)|\(\)|\)\(|[^\+\-\*\/\(]\()/)){
throw '不正な入力:'+match[0];
}
r.replace(/[\+\-\*\/]{2,}/g,function(match){
if(match.length>2 || match.substr(-1)!=='-')throw '不正な入力:'+match;
return match;
});
var n=0;
r.replace(/[\(\)]/g,function(match){
if(match=='('){n++;}
else if(match==')'){n--;}
if(n<0){throw '閉じられていない括弧があります';}
return match;
});
if(n!=0){throw '閉じられていない括弧があります';}
alert(r+' = '+eval(a));
}catch(e){
if(typeof(e)=='string'){alert(e);}
else{alert(e.message);}
}
}
// -->
</script>

処理止めてメッセージ返すほうが
どこで引っかかったかわかるから好き

検索巡回にわざわざreplace使うのはどうかとも思ったけど
それ以外に一致部分をcallbackで都度さらに
判定する手段が思い当たらなかったし
多分どっか引っかかったところで即処理を中断できる方が
効率いいと思ったのでとりあえずreplaceで

ここまで判定したらelse{alert(e.message);}に行くことないかな?

投稿日時 - 2017-09-04 22:19:08

ANo.6

以前JavaScriptでマクロのような記述を見た事があったのですが、もしかしてjQueryなどをインクルードしていたのかもしれません(jQueryでevalが影響を受けるのかは分かりませんが)。

まあ、どちらにしろ「四則演算子、数字、括弧」以外は除去されるので、エスケープとかの必要はないでしょう(バグがなければの話ですが)。

投稿日時 - 2017-09-03 08:55:33

ANo.5

>エスケープしたいのですが

エスケープの意味はコーテションで囲むみたいな意味なのか?わかりませんが、

>r = r.replace(/([^0-9\.\-\/\*\+\(\) ]+)/g, ' ');
>r = r.replace(/([\*\/])[ \+\-\*\/]*([\+\-])[ ]*([0-9\.\(]+)/g, '$1$2$3');
>r = r.replace(/[\+\-][ \+\-\*\/]*([\+\-])[ ]*([0-9\.\(]+)/g, '$1$2');
>r = r.replace(/([\+\-\*\/])[ \+\-\*\/]*[\*\/][ ]*([0-9\.\(]+)/g, '$1$2');
>r = r.replace(/(^|\()[ \+\-\*\/]*([\+\-])/g, '$1$2');
>r = r.replace(/(^|\()[ \+\-\*\/]*[\*\/]/g, '$1');
>r = r.replace(/([ ]+)/g, ' ');

↑これは「四則演算子、数字、括弧」以外は除去されるので、エスケープとかの必要はないでしょう(まあバグがなければの話ですが)。

>バグがありましたので、修正しました (2)。

バグではありませんが、チョット修正しました。



「四則演算子、数字、括弧」以外は除去されます。<br>
また式として成立しない文字列は計算できません。<br>
<input type="text" name="gakunen" value="" onKeyPress="Calculator(this.value, event.keyCode)">

<script type="text/javascript">
<!--
function Calculator(a, kcode){
var r;
if (!(13==kcode)){return;}
// ↑「13:Enterキー」でない場合は「return」
r = a;
r = r.replace(/([^0-9\.\-\/\*\+\(\) ]+)/g, ' ');
r = r.replace(/([\*\/])[ \+\-\*\/]*([\+\-])[ ]*([0-9\.\(]+)/g, '$1$2$3');
r = r.replace(/[\+\-][ \+\-\*\/]*([\+\-])[ ]*([0-9\.\(]+)/g, '$1$2');
r = r.replace(/(^|\()[ \+\-\*\/]*([\+\-])/g, '$1$2');
r = r.replace(/(^|\()[ \+\-\*\/]*[\*\/]/g, '$1');
r = r.replace(/([\+\-\*\/])[ \+\-\*\/]*[\*\/][ ]*([0-9\.\(]+)/g, '$1$2');
r = r.replace(/([ ]+)/g, ' ');
try{
alert(r+' = '+eval(r));
}catch(ex){
alert(ex.message+' : '+r);
}
}
// -->
</script>

投稿日時 - 2017-09-03 06:19:53

ANo.4

バグがありましたので、修正しました (2)。



「四則演算子、数字、括弧」以外は削除されます。<br>
また式として成立しない文字列は計算できません。<br>
<input type="text" name="gakunen" value="" onKeyPress="Calculator(this.value, event.keyCode)">

<script type="text/javascript">
<!--
function Calculator(a, kcode){
var r;
if (!(13==kcode)){return;}
// ↑「13:Enterキー」でない場合は「return」
r = a;
r = r.replace(/([^0-9\.\-\/\*\+\(\) ]+)/g, ' ');
r = r.replace(/([\*\/])[ \+\-\*\/]*([\+\-])[ ]*([0-9\.\(]+)/g, '$1$2$3');
r = r.replace(/[\+\-][ \+\-\*\/]*([\+\-])[ ]*([0-9\.\(]+)/g, '$1$2');
r = r.replace(/([\+\-\*\/])[ \+\-\*\/]*[\*\/][ ]*([0-9\.\(]+)/g, '$1$2');
r = r.replace(/(^|\()[ \+\-\*\/]*([\+\-])/g, '$1$2');
r = r.replace(/(^|\()[ \+\-\*\/]*[\*\/]/g, '$1');
r = r.replace(/([ ]+)/g, ' ');
try{
alert(r+' = '+eval(r));
}catch(ex){
alert(ex.message+' : '+r);
}
}
// -->
</script>

投稿日時 - 2017-09-03 03:45:40

ANo.3

>>とりあえず1*-1ができない

>それは考えてませんでした、下記で対応できます。

バグがありましたので、修正しました。



「四則演算子、数字、括弧」以外は削除されます。<br>
また式として成立しない文字列は計算できません。<br>
<input type="text" name="gakunen" value="" onKeyPress="Calculator(this.value, event.keyCode)">

<script type="text/javascript">
<!--
function Calculator(a, kcode){
var r;
if (!(13==kcode)){return;}
// ↑「13:Enterキー」でない場合は「return」
r = a;
r = r.replace(/([^0-9\.\-\/\*\+\(\) ]+)/g, ' ');
r = r.replace(/([\+\-\*\/])[ \+\-\*\/]*([\+\-])[ ]*([0-9\.\(]+)/g, '$1$2$3');
r = r.replace(/([\+\-\*\/])[ \+\-\*\/]*[\*\/][ ]*([0-9\.\(]+)/g, '$1$2');
r = r.replace(/^[ \+\-\*\/]*([\+\-])/g, '$1');
r = r.replace(/(\()[ \+\-\*\/]*([\+\-])/g, '$1$2');
r = r.replace(/([ ]+)/g, ' ');
try{
alert(r+' = '+eval(r));
}catch(ex){
alert(ex.message+' : '+r);
}
}
// -->
</script>

投稿日時 - 2017-09-02 23:02:11

お礼

その後どうでしょうか?お忙しいところ恐縮ですがよろしくお願いします。

また、教えていただいたエスケープはなかなか難しくどこに記載したらよいかなどわからないのですが、
htmlcharacterでphpはhtmlタグを安全な文字列に簡単に変換できるようですがjavascriptにはそのような便利な関数はないのでしょうか?

投稿日時 - 2017-09-10 18:01:03

ANo.2

>とりあえず1*-1ができない

それは考えてませんでした、下記で対応できます。



「四則演算子、数字、括弧」以外は削除されます。<br>
また式として成立しない文字列は計算できません。<br>
<input type="text" name="gakunen" value="" onKeyPress="Calculator(this.value, event.keyCode)">

<script type="text/javascript">
<!--
function Calculator(a, kcode){
var r;
if (!(13==kcode)){return;}
// ↑「13:Enterキー」でない場合は「return」
r = a;
r = r.replace(/([^0-9\.\-\/\*\+\(\) ]+)/g, ' ');
r = r.replace(/([\+\-\*\/])[ \+\-\*\/]*([\+\-])[ ]*([0-9\.\(]+)/g, '$1$2$3');
r = r.replace(/([\+\-\*\/])[ \+\-\*\/]*[\*\/][ ]*([0-9\.\(]+)/g, '$1$2');
r = r.replace(/^[ \+\-\*\/]*([\+\-])/g, '$1');
r = r.replace(/([ ]+)/g, ' ');
try{
alert(r+' = '+eval(r));
}catch(ex){
alert(ex.message+' : '+r);
}
}
// -->
</script>

投稿日時 - 2017-09-02 22:54:54

補足

下記のお礼コメントの件教えていただければ幸いです。

ここがわからないと前に進めないので、お忙しいところ恐縮ですがよろしくお願いします。

今処理はeval の前においておけばいいのでしょうか?

投稿日時 - 2017-09-05 13:01:08

お礼

>>>
>r = r.replace(/([^0-9\.\-\/\*\+\(\) ]+)/g, ' ');
>r = r.replace(/([\*\/])[ \+\-\*\/]*([\+\-])[ ]*([0-9\.\(]+)/g, '$1$2$3');
>r = r.replace(/[\+\-][ \+\-\*\/]*([\+\-])[ ]*([0-9\.\(]+)/g, '$1$2');
>r = r.replace(/([\+\-\*\/])[ \+\-\*\/]*[\*\/][ ]*([0-9\.\(]+)/g, '$1$2');
>r = r.replace(/(^|\()[ \+\-\*\/]*([\+\-])/g, '$1$2');
>r = r.replace(/(^|\()[ \+\-\*\/]*[\*\/]/g, '$1');
>r = r.replace(/([ ]+)/g, ' ');


文字列.replace( 検索文字列 , 置換文字列 )
文字列の置換を行います

という事なので変数rの中に入っている文字列?テキストエリアのテキスト?
を上記の文字に変換するという事でしょうか?
恐らくトンチンカンですいません。




>>>
if (!(13==kcode)){return;}

これは上記の許可する13文字に該当しなかったら何かを返すのですか??


初心者なのでさっぱりわかりません。

投稿日時 - 2017-09-03 12:24:58

ANo.1

とりあえず1*-1ができない

投稿日時 - 2017-09-02 12:02:04

お礼

マイナスをかけることが出来ないという事でしょうか?

他はできるのですね。

投稿日時 - 2017-09-02 12:24:23