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

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

新規登録して質問してみよう
ただいま回答率
85.47%
標準入力

標準入力(stdin)は、プログラムが標準的に用いるデータ入力元。リダイレクトしない限り、プログラムを起動した端末のキーボードが標準入力になります。UNIX系OSやC言語に実装されて普及した概念ですが、他のOSや言語も含めた総称としても使われます。

Java

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

Eclipse

Eclipseは、IBM社で開発された統合開発環境のひとつです。2001年11月にオープンソース化されました。 たくさんのプラグインがあり自由に機能を追加をすることができるため、開発ツールにおける共通プラットフォームとして位置づけられています。 Eclipse自体は、Javaで実装されています。

Q&A

解決済

4回答

2290閲覧

Java言語で、標準入力から受け取った数式を四則演算の原則に則って計算したい。

takayuki1107

総合スコア28

標準入力

標準入力(stdin)は、プログラムが標準的に用いるデータ入力元。リダイレクトしない限り、プログラムを起動した端末のキーボードが標準入力になります。UNIX系OSやC言語に実装されて普及した概念ですが、他のOSや言語も含めた総称としても使われます。

Java

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

Eclipse

Eclipseは、IBM社で開発された統合開発環境のひとつです。2001年11月にオープンソース化されました。 たくさんのプラグインがあり自由に機能を追加をすることができるため、開発ツールにおける共通プラットフォームとして位置づけられています。 Eclipse自体は、Javaで実装されています。

0グッド

1クリップ

投稿2023/02/06 01:16

編集2023/02/06 01:19

Java言語で、標準入力から受け取った数式を四則演算の原則に則って計算したい。

ここに実現したいことを箇条書きで書いてください。

  • 標準入力からString型の数式を受け取って(2×3+1、とか、100×50/20、(20+30)×5、2(3+5)/4みたいな、=はつかない、×や÷が来たら乗算・除算にする)それを四則演算の原則に則って計算(*や/は+や-に優先する、とか、()内の計算が優先とか)したいです。

↑上の文章で乗算を表そうとしてアスタリスクを書くと表示されないので×としています。

前提

開発環境はeclipse、OSはwindows11、ちなみにiniファイルを編集して文字コードをUTF-8にしました。

私のJavaスキル→勉強し始めて2週間たたない程度。変数宣言、算術演算子、if文での条件分岐、forやwhileなどの繰り返し処理、メソッドの使い方、クラスを分けての開発の仕方などを学びました。
ちなみに、独学ですがPHPは約1年、Pythonは半年ほど勉強しており、基本的な文法は抑えており、PHPはスクラッチで各種バリデーションやログイン機能を備えたアプリを開発したり、Laravelを用いて簡単なアプリを開発したことがあり、PythonはフレームワークにStreamlit、ライブラリにpandasやnumpy、altairなどを使っての簡単なwebアプリ開発の経験があります。

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

特に何か問題が発生しているわけではなく、この問題を解くための手順だったり、考え方に関してご教授いただけたらなと思います。
私としては、①標準入力で受け取った数式をsplitなどで1文字ずつ分割して配列に格納、②*, /, +, -, (, )以外の値をint型に変換、③配列の値をループで回してint型の要素が連続したら数値を連結、*や/が来たら優先して計算、()も優先して計算、みたいな感じの流れでコードを書こうと思っているのですが、こちら実現したいことの欄でも述べたように、どうすれば四則演算の原則に従いつつうまくコードを書けるのかが分かりません(ライブラリなどを使えば簡単に書けるのかもしれませんが、あくまで私がこれまで学習した変数宣言、算術演算子、if文での条件分岐、forやwhileなどの繰り返し処理、メソッドの使い方、クラスを分けての開発などの知識のみで実装したいです。

該当のソースコード

まだ配列に格納するところまでしか実装しておりません。
この後の流れとしてどのように実装すればよいのか、またそもそも配列に1文字ずつ格納するやり方は効率的かどうかをご教授いただきたいです。

Java

1package chukan_kadai; 2 3import java.util.Scanner; 4 5public class chukan_kadai { 6 public static void main(String args[]) { 7      System.out.println("数式を入力してください"); 8 9      Scanner scanner = new Scanner(System.in); 10      String formula = scanner.nextLine(); 11 12      String[] formulaArray = formula.split(""); 13 } 14}

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

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

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

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

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

Zuishin

2023/02/06 01:39 編集

二週間でやるような課題じゃありませんが、テキストを間違えていませんか? 自信があるのであれば「逆ポーランド記法」を調べてみましょう。
takayuki1107

2023/02/06 02:39

いえ、こちらテキストなどではなく、あるYouTube動画の講義です。 やはりこちら難易度高いですよね笑、安心しました。 逆ポーランド記法ですね、調べてみます。 コメントいただきありがとうございます。
jimbe

2023/02/06 05:08

具体的なコードの問題で無いのでしたら、QA でなく意見交換にした方が良いのではないでしょうか。
guest

回答4

0

ベストアンサー

字句解析、構文解析をして構文木を作り、構文木を評価して結果を出すのが一般的な手順です。
コンパイラ作成に関する書籍を読んだり、上記キーワードを調べてみてください。

四則演算に関しては、構文木を作らずにスタックを使って上手くやる方法もあります。

またそもそも配列に1文字ずつ格納するやり方

String#charAt() で一文字ずつアクセスできるので、配列にする必要はありません。

投稿2023/02/06 01:45

編集2023/02/06 02:58
int32_t

総合スコア20941

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

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

takayuki1107

2023/02/06 02:37

ご回答ありがとうございます。 キーワードについてしっかり理解し実装を頑張ります。 改めてご回答ありがとうございます。
takayuki1107

2023/02/06 03:31

ちなみになんですが、おすすめの書籍はございますでしょうか。
int32_t

2023/02/06 04:00

おすすめの情報は持ち合わせていません。 昔『コンパイラ― 原理・技法・ツール』を読んでわかり難かった記憶があります。 本当にコンパイラを作りたいのではない限り、コンパイラの専門書よりはいろいろなアルゴリズムが載っている本で字句解析構文解析についても触れているもののほうがよいでしょうね。
takayuki1107

2023/02/07 06:45

かしこまりました。ありがとうございます。
guest

0

ざっくり RPN です。
enum 使っちゃってますが。

java

1import java.util.*; 2import java.util.regex.Matcher; 3import java.util.regex.Pattern; 4 5public class Main { 6 public static void main(String[] args) { 7 String[] testdata = { "1+2.5*-3", "100*50/20", "(20+30)*5", "2(3+5)/4" }; 8 for(String formula : testdata) { 9 RPN rpn = new RPN(formula); 10 System.out.println(rpn + "=" + rpn.calc()); 11 } 12 } 13 14 private static class RPN { 15 private interface Element { 16 void operate(Deque<String> stack); 17 } 18 19 private static class Value implements Element { 20 private final String v; 21 Value(String v) { 22 this.v = v; 23 } 24 @Override 25 public void operate(Deque<String> stack) { 26 stack.push(v); 27 } 28 @Override 29 public String toString() { 30 return v; 31 } 32 } 33 34 private enum Operator implements Element { 35 PLS("+",1) { @Override protected double calc(double a, double b) { return a + b; } }, 36 MIN("-",1) { @Override protected double calc(double a, double b) { return a - b; } }, 37 MUL("*",2) { @Override protected double calc(double a, double b) { return a * b; } }, 38 DIV("/",2) { @Override protected double calc(double a, double b) { return a / b; } }, 39 BS("(",0), 40 BE(")",0); 41 42 private final String text; 43 private final int pri; 44 Operator(String text, int pri) { 45 this.text = text; 46 this.pri = pri; 47 } 48 49 static Operator of(char c) { 50 for(Operator ope : values()) if(ope.text.charAt(0) == c) return ope; 51 return null; 52 } 53 54 @Override 55 public void operate(Deque<String> stack) { 56 double b = Double.parseDouble(stack.pop()); 57 double a = Double.parseDouble(stack.pop()); 58 stack.push("" + calc(a, b)); 59 } 60 61 protected double calc(double a, double b) { 62 throw new UnsupportedOperationException(); 63 } 64 65 @Override 66 public String toString() { 67 return text; 68 } 69 } 70 71 private static class Translator { 72 private static class Source { 73 private static Pattern NUM_PATTERN = Pattern.compile("-?\\d+(:?\\.\\d+)?"); 74 75 private final String formula; 76 private int index; 77 78 Source(String formula) { 79 this.formula = formula; 80 } 81 82 boolean isEnd() { return index >= formula.length(); } 83 char getChar() { return formula.charAt(index); } 84 Operator nextOperator() { 85 Operator op = Operator.of(formula.charAt(index++)); 86 if(op == null) throw new IllegalArgumentException("Operator Error: index=" + index); 87 return op; 88 } 89 Value nextNumber() { 90 Matcher m = NUM_PATTERN.matcher(formula.substring(index)); 91 if(!m.find() || m.start() != 0) throw new IllegalArgumentException("Number Error: index=" + index); 92 index += m.group().length(); 93 return new Value(m.group()); 94 } 95 } 96 97 private static class Destination { 98 private Deque<Operator> stack = new ArrayDeque<>(); 99 private List<Element> list = new ArrayList<>(); 100 101 void put(Operator op) { 102 if(op == Operator.BE) { 103 while(!stack.isEmpty() && (op=stack.pop()) != Operator.BS) list.add(op); 104 if(op != Operator.BS) throw new IllegalStateException("Formula Error: Unmatched parentheses."); 105 return; 106 } 107 if(op != Operator.BS) { 108 while(!stack.isEmpty() && stack.peek().pri >= op.pri) list.add(stack.pop()); 109 } 110 stack.push(op); 111 } 112 void put(Value v) { 113 list.add(v); 114 } 115 List<Element> complete() { 116 while(!stack.isEmpty()) list.add(stack.pop()); 117 return new ArrayList<>(list); 118 } 119 } 120 121 private enum Mode { 122 NUM { 123 Mode translate(Source src, Destination dst) { 124 if(src.getChar() == '(') { 125 dst.put(src.nextOperator()); 126 return this; 127 } 128 dst.put(src.nextNumber()); 129 return OP; 130 } 131 }, 132 OP { 133 Mode translate(Source src, Destination dst) { 134 Operator op = src.nextOperator(); 135 if(op == Operator.BE) { 136 dst.put(op); 137 return this; 138 } 139 if(op == Operator.BS) dst.put(Operator.MUL); 140 dst.put(op); 141 return NUM; 142 } 143 }; 144 145 abstract Mode translate(Source src, Destination dst); 146 } 147 148 static List<Element> translate(String formula) { 149 Mode mode = Mode.NUM; 150 Source src = new Source(formula); 151 Destination dst = new Destination(); 152 while(!src.isEnd()) mode = mode.translate(src, dst); 153 return dst.complete(); 154 } 155 } 156 157 private final String formula; 158 private List<Element> list; 159 160 RPN(String formula) { 161 this.formula = formula; 162 list = Translator.translate(formula); 163 } 164 165 String calc() { 166 Deque<String> stack = new ArrayDeque<>(); 167 for(Element elm : list) elm.operate(stack); 168 return stack.pop(); 169 } 170 171 @Override 172 public String toString() { 173 return formula + "=" + list; 174 } 175 } 176}
1+2.5*-3=[1, 2.5, -3, *, +]=-6.5 100*50/20=[100, 50, *, 20, /]=250.0 (20+30)*5=[20, 30, +, 5, *]=250.0 2(3+5)/4=[2, 3, 5, +, *, 4, /]=4.0

投稿2023/02/06 13:47

編集2023/02/06 19:46
jimbe

総合スコア12696

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

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

takayuki1107

2023/02/07 06:47

ご回答いただきありがとうございます。現時点の僕の知識ではまだコードの大半が理解できてないので、今後学習を進める中でこちらのコードの理解を深めていければと思います。改めてご回答ありがとうございます!
guest

0

字句解析と構文解析の例を書いて見ました。
ただし、演算子の順位や括弧はない数式の構文解析とします。

Java

1import java.util.Scanner; 2 3class Main { 4 public static void main(String[] args) { 5 System.out.println("数式を入力してください"); 6 Scanner scanner = new Scanner(System.in); 7 String formula = scanner.nextLine(); 8 Expr e = new Expr(formula); 9 int val = e.syn(); 10 if (e.tok != 0) System.out.println("syntax error"); 11 else System.out.println(val); 12 } 13} 14 15class Expr { // 数式クラス (expression) 16 String str; int len, pos, val; char tok; 17 18 Expr(String s) { str = s; len = s.length(); pos = 0; } 19 20 char lex() { // 字句解析 (lexical analyzer) 21 while (pos < len) 22 if ((tok = str.charAt(pos++))>='0' && tok<='9') { 23 for (val = tok - '0'; pos < len && 24 (tok = str.charAt(pos))>='0' && tok<='9'; pos++) 25 val = val * 10 + (tok - '0'); 26 return tok = '0'; 27 } 28 else if (tok != ' ') return tok; 29 return tok = 0; // end of string 30 } 31 32 int syn() { // 構文解析 (syntax analyzer) 33 int v = 0; 34 for (char op = '+'; lex() != 0; ) 35 if (tok == '0') 36 switch (op) { 37 case '+' : v += val; break; 38 case '-' : v -= val; break; 39 case '*' : v *= val; break; 40 case '/' : v /= val; break; 41 default: return v; 42 } 43 else op = tok; 44 return v; 45 } 46}

追記
演算子の優先順位と括弧の処理も追加した構文解析です。

Java

1import java.util.Scanner; 2 3class Main { 4 public static void main(String[] args) { 5 System.out.println("数式を入力してください"); 6 Scanner scanner = new Scanner(System.in); 7 String formula = scanner.nextLine(); 8 Expr e = new Expr(formula); 9 int val = e.syn(0); 10 if (e.tok != 0) System.out.println("syntax error"); 11 else System.out.println(val); 12 } 13} 14 15class Expr { // 数式クラス (expression) 16 String str; int len, pos, val; char tok; 17 18 Expr(String s) { str = s; len = s.length(); pos = 0; } 19 20 char lex() { // 字句解析 (lexical analyzer) 21 while (pos < len) 22 if ((tok = str.charAt(pos++))>='0' && tok<='9') { 23 for (val = tok - '0'; pos < len && 24 (tok = str.charAt(pos))>='0' && tok<='9'; pos++) 25 val = val * 10 + (tok - '0'); 26 return tok = '0'; 27 } 28 else if (tok != ' ') return tok; 29 return tok = 0; // end of string 30 } 31 32 final static char[] op = { '+', '-', '*', '/' }; 33 34 int syn(int i) { // 構文解析 (syntax analyzer) 35 int v; 36 if (i < 4) 37 for (v = syn(i+2); tok == op[i] || tok == op[i+1]; ) 38 if (tok == '+') v += syn(i+2); 39 else if (tok == '-') v -= syn(i+2); 40 else if (tok == '*') v *= syn(i+2); 41 else v /= syn(i+2); 42 else if (lex() == '0') { v = val; lex(); } 43 else if (tok == '(') { 44 v = syn(0); 45 if (tok == ')') lex(); 46 else tok = 1; 47 } 48 else v = tok = 1; 49 return v; 50 } 51}

投稿2023/02/06 08:33

編集2023/02/06 15:21
kazuma-s

総合スコア8224

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

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

takayuki1107

2023/02/07 06:48

ご回答いただきありがとうございます。こちら参考にさせていただければと思います。
guest

0

字句解析 → 構文解析 → スタック

投稿2023/02/06 01:50

退会済みユーザー

退会済みユーザー

総合スコア0

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

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

takayuki1107

2023/02/06 02:37

ご回答ありがとうございます。 キーワードについて調べて理解を深めたいと思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.47%

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

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

質問する

関連した質問