teratail header banner
teratail header banner
質問するログイン新規登録

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

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

新規登録して質問してみよう
ただいま回答率
85.30%
Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Q&A

解決済

3回答

18975閲覧

JavaのStringの計算式の答えを導き出したい

tmp-user

総合スコア44

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

0グッド

1クリップ

投稿2020/03/11 22:35

編集2020/03/11 23:22

0

1

お世話になっております。

※先日近い質問をさせていただいたのですが正直少々いただいた回答が難解でしたので
返答の為にも一つ前段階の質問をさせてください。

JavaのStringで書かれた数式から計算式を求めよ、という問題なのですが
intとStringを判断した後の処理がわかりません。

calc("10 + 20"); //30
calc("10 * 20"); //200

条件
/は出てこない
・スペースは最初に消す

考えたのはisDigitを用いて数値かどうかを判断し、Integer.parseIntにて
intに変換する、というものですが、変換したものをどうすれば計算できるのかが
わかりませんでした。

java

1import java.util.*; 2 3public class Main { 4 public static void main(String[] args) throws Exception { 5 calc("10 + 20") 6     calc("10 * 20") 7 } 8 9 public static void calc(String str){ 10 String str0 = str.replaceAll(" ",""); //スペースの削除 11 String s =""; 12 String num1 = ""; 13 14 for(int i = 0; i < str0.length() ;i++){ 15   //一文字ずつ評価していく 数字or演算 16   //連続で数字→結合   、演算子が決まる→次の処理に行く 17 18 if(Character.isDigit(str0.charAt(i))){ 19 //ここの処理が不明 20          //連続した数字を結合してnum1等に代入? 21 } else { 22 s = str0.charAt(i); 23 } 24 } 25 26 // int result = Integer.parseInt(/*不明*/) + s + Integer.parseInt(/*不明*/); 27 System.out.println(result); 28 } 29 30}

お手数ですが教えていただきたく思います。
知識が甘いので極力シンプルにかければ・・・・と考えております。

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yureighost

2020/03/11 23:11

もう一つ条件を確認ですが、数字と演算子の間は必ずスペースが入っていると思っていいですかね。
tmp-user

2020/03/11 23:18

はい、必ずスペースがありそれを最初に消せ、という事だそうです。
hoshi-takanori

2020/03/11 23:21

演算子(+ や * など)は一個しか含まれないってことであれば、その前後をそれぞれ数値に変換して計算すればいいですが、複数ありうるとしたらちゃんとパーサーを書かなきゃいけないので、シンプルにはなりません。
tmp-user

2020/03/11 23:25

仮に1つしかないとした場合はどのような記述になるのでしょうか。
Zuishin

2020/03/11 23:29

前の質問を見てみましたが、まず字句解析し、カッコを外すために逆ポーランド記法に直し、その上で計算するのが一番簡単な方法です。字句解析で詰まっている人に解ける問題ではないので、あなたが解くべきレベルの問題ではありません。学習進度が早すぎるので、もう少し前の段階を自分のものにしてから挑戦してください。
hoshi-takanori

2020/03/11 23:37

演算子(+ や * など)が一個しかない場合、 ・演算子の場所を探す(indexOf メソッド) ・その前後の文字列を取り出し(substring メソッド)、整数に変換 ・計算 って流れですね。まず足し算だけの場合をやって、それを拡張して他の計算もできるようにすればいいのでは。 最終的にもっと複雑な計算をしたいならパーサーを書く必要がありますが、それ以前に演算子が一つの場合が解けないようではどうしようもないので、ひとつひとつ段階を踏んで学習を進めたらいいと思います。
Y.H.

2020/03/12 01:06

この質問(回答有も放置)↓と質問内容が同じに見えるんですがこの質問とどう違うとでしょうか? Javaで文字列を数式に変換したい https://teratail.com/questions/246043
guest

回答3

0

考えたのはisDigitを用いて数値かどうかを判断し、Integer.parseIntにて
intに変換する、というものですが、変換したものをどうすれば計算できるのかがわかりませんでした。

四則演算の式を見たときに、ご自分の頭の中でどのように計算するかをプログラムで表現すれば良いのです。
(それが分からない、と言うご質問なのだとは思いますが、コメントでもご指摘いただいているように質問者さんが今、取り組む課題としては難しすぎるかもしれません)

"1 + 2" を考えてみます。一般的にこの計算式を見た場合、「最初に出てくるものは、足される数である文字列の"1"、次に出てくる文字列は演算子で、"+"。と言うことは次の文字列は足す数の文字列 "2"」が言えます。取り扱いに際して3つの項目がそろっていなければならないということです。足りなければ計算はできないので、そもそも計算しないか、エラー報告するなりすることになるのでしょう。

文字列を1文字1文字取り出しているのであれば、"123"のように2桁以上のものは完成するまで当然、取り続けて連結していく必要があります。数文字が終わりと判断するのは演算子が来たか、文字列の終端に達したか、と言うことになるでしょう。「足される数」、「演算子"+"」、「足す数」がそろえば、足し算をして終わりです。字句の並び、トークン(Token)を取り扱うことになります。

質問者さんのコードをもとに四則演算をするcalcと、おまけで"10 + 20 + 30 - 40 * 3 / 2"...などと連続して式を入力した場合でも計算できるcalc2のコード例を示します。ただし、calc2については乗除("*/")の計算の優先順位を考慮していません。優先順位やカッコ(())を含めた計算になってくると、先のご質問
Javaで文字列を数式に変換したい - teratail#246043
の回答でいただいたような解法が必要になってくるはずです。まずはcalcのようなメソッドは自力で作れるようにならないと、完成はちょっと難しいのでは、と思えるのが正直なところです。

Java

1import java.util.*; 2 3public class Main { 4 public static void main(String[] args) throws Exception { 5 calc("10 + 20"); 6 calc("10 * 20"); 7 calc("20 - 13"); 8 calc("20 / 4"); 9 10 // 演算子の優先順位は考慮しない計算 11 calc2("11 + 210"); 12 calc2("10 + 20 - 5"); 13 calc2("1 + 20 + 30 - 40 * 12 / 4"); 14 } 15 16 // 質問者さんオリジナルのコードの延長(割り算'/'を追加) 17 public static void calc(String str) { 18 String str0 = str.replaceAll(" ",""); //スペースの削除 19 String num1 = ""; 20 char ope = 0; 21 22 int value1 = -1; 23 int value2 = -1; 24 25 for(int i = 0; i < str0.length() ;i++){ 26 //一文字ずつ評価していく 数字or演算 27 //連続で数字→結合   、演算子が決まる→次の処理に行く 28 29 if(Character.isDigit(str0.charAt(i))){ 30 //ここの処理が不明 31 //連続した数字を結合してnum1等に代入? 32 num1 += str0.charAt(i); 33 34 } else { 35 // 数文字でなければ演算子のはず 36 value1 = Integer.parseInt(num1); 37 ope = str0.charAt(i); 38 num1 = ""; 39 } 40 } 41 42 value2 = Integer.parseInt(num1); 43 int result = 0; 44 if (ope == '+') { 45 result = value1 + value2; 46 } else if (ope == '-') { 47 result = value1 - value2; 48 } else if (ope == '*') { 49 result = value1 * value2; 50 } else if (ope == '/') { 51 result = value1 / value2; 52 } 53 54 // int result = value.parseInt(/*不明*/) + s + value.parseInt(/*不明*/); 55 System.out.println("calc(): result=" + result); 56 } 57 58 // 演算子の優先順位を考慮しない四則演算 59 public static void calc2(String str) { 60 String ope = ""; 61 String sv1 = ""; 62 int result = 0; 63 64 // スペース(" ")を区切りとしてトークン分割 65 String[] tokens = str.split(" ", -1); 66 //for (String token: tokens) { 67 for (int i = 0; i < tokens.length; i++) { 68 String token = tokens[i]; 69 70 if (sv1.isEmpty()) { 71 // 1つ目の数文字列であれば、まだ計算しない 72 sv1 = token; 73 } else if (ope.isEmpty()) { 74 // 演算子であれば、1つ目の数文字列は存在することになるが、まだ計算しない 75 ope = token; 76 } else { 77 // 1つ目の数文字列、演算子は確定しているので、計算できる。 78 int value1 = Integer.parseInt(sv1); 79 int value2 = Integer.parseInt(token); 80 if (ope.equals("+")) { 81 result = value1 + value2; 82 } else if (ope.equals("-")) { 83 result = value1 - value2; 84 } else if (ope.equals("*")) { 85 result = value1 * value2; 86 } else if (ope.equals("/")) { 87 result = value1 / value2; 88 } 89 90 ope = ""; 91 // 現在の答えを次の1つ目の数文字列として扱うことで、連続した計算を可能にする 92 sv1 = String.valueOf(result); 93 } 94 } 95 96 String s = String.format("calc2(): %s = %d", str, result); 97 System.out.println(s); 98 } 99}

Windowsのコマンドプロンプト上で実行すると、以下のようになります。

CMD

1C:>javac Main.java 2 3C:>java Main 4calc(): result=30 5calc(): result=200 6calc(): result=7 7calc(): result=5 8calc2(): 11 + 210 = 221 9calc2(): 10 + 20 - 5 = 25 10calc2(): 1 + 20 + 30 - 40 * 12 / 4 = 33 11 12C:>

投稿2020/03/12 02:08

編集2020/03/12 02:20
dodox86

総合スコア9416

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

dodox86

2020/03/12 02:09

あれれ、間に合いませんでしたw(解決済み)
guest

0

ベストアンサー

Java

1class Main { 2 public static void main(String[] args) throws Exception { 3 new Main(); 4 } 5 6 Main() { 7 calc("10 + 20"); 8 calc("10 * 20"); 9 calc("10 , 20"); 10 calc("10 + *"); 11 } 12 13 String str; // 与えられた文字列(string) 14 int len; // 与えられた文字列の長さ(length) 15 int pos; // 読み取り位置(position) 16 char tok; // トークン(token): 数値は '0'、その他はその文字 17 int val; // トークンの値(value) 18 19 char get() { // 字句解析(lexical analizer, token reader) 20 while (pos < len) 21 if ((tok = str.charAt(pos++)) != ' ' ) { // スペース無視 22 if (!Character.isDigit(tok)) return tok; 23 for (val = tok - '0'; ; ) { 24 if (pos == len) return tok = '0'; 25 tok = str.charAt(pos++); 26 if (!Character.isDigit(tok)) { pos--; return tok = '0'; } 27 val = val * 10 + (tok - '0'); 28 } 29 } 30 return tok = 0; 31 } 32 33 void calc(String s) { 34 str = s; 35 len = s.length(); 36 pos = 0; 37 38 if (get() != '0') { error("number expected"); return; } // 数値取得 39 int result = val; 40 char op = get(); // 演算子(operator)取得 41 if (get() != '0') { error("number expected"); return; } // 数値取得 42 if (op == '+') result += val; 43 else if (op == '-') result -= val; 44 else if (op == '*') result *= val; 45 else { error("unknown operator"); return; } 46 System.out.println(result); 47 } 48 49 void error(String msg) { 50 System.out.println("Error: " + msg); 51 } 52}

get は、呼び出されるたびに与えられた文字列から数値や演算子を返します。

どこが分からないのかを質問してください。

追記
get の中の retrun '0'; を return tok = '0'; に修正しました。

追記2
実は Java には Scanner というクラスがあり、区切り文字(デフォルトはスペース)
で区切られた数字列や文字列を切り出すことができます。
それを使えば次のようなコードが書けます。

Java

1import java.util.Scanner; 2 3class Main { 4 public static void main(String[] args) throws Exception { 5 calc("10 + 20"); 6 calc("10 * 20"); 7 } 8 9 static void calc(String str) { 10 Scanner s = new Scanner(str); 11 12 int result = s.nextInt(); 13 String op = s.next(); 14 int val = s.nextInt(); 15 16 if (op.equals("+")) result += val; 17 else if (op.equals("*")) result *= val; 18 else { System.out.println("unknown operator"); return; } 19 20 System.out.println(result); 21 } 22}

これなら理解できますか?

投稿2020/03/12 01:42

編集2020/03/12 03:53
kazuma-s

総合スコア8222

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tmp-user

2020/03/12 02:03

ありがとうございます。 ようやく理解が進みました。 頂いたものをベースにいろいろと確認、変更して学ぼうと思います。
guest

0

間に挟まってる演算子によって、
"*" なら数値を掛けて、
"+" なら数値を足せばいいのです

投稿2020/03/11 23:14

y_waiwai

総合スコア88178

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tmp-user

2020/03/11 23:23

考え方としては分かるのですが実現の仕方がイマイチわからずでして・・・。 まず1文字ずつ`isDigit`で判定していますが`"10"`が出てきた際に1と0をどのように結合するか 1つ目の数値は文字列結合できそうなのですが2つ目の数値`"20"`が出てきた際にどう分岐 すればいいのかがわかりません。
y_waiwai

2020/03/11 23:39

数値の文字列を数値に変換してくれる関数があります。 なので、まずは数値とそうじゃない文字列で分けます "10+20" という文字列なら、"10"と”+”と”20” の3つの文字列に分けることを考えましょう
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.30%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問