Java中替代C++ std::cin.unget()的方案咨询
Java替代C++ std::cin.unget()的方案(适配表达式解析场景)
你要把一段C数学表达式解析代码转成Java,但C里用到的std::cin.unget()在Java中没有直接对应的方法。先明确C++里unget()的作用:它会把刚读取的字符放回输入流,让下一次读取操作能重新获取这个字符——比如你的代码里,term()读了一个非*//的字符,就用unget()放回去留给后续逻辑处理;factor()里读了数字的第一个字符后,放回去再完整读取整个浮点数。
下面是两种可行的Java替代方案:
方案1:使用PushbackReader(模拟流回退)
Java的PushbackReader类支持unread()方法,功能和C的unget()完全一致,可以把字符推回到输入流中。以下是对应原C代码的Java实现:
import java.io.IOException; import java.io.PushbackReader; import java.io.StringReader; public class ExpressionParser { private final PushbackReader reader; public ExpressionParser(String input) { this.reader = new PushbackReader(new StringReader(input)); } // 读取下一个字符(对应原C++的token()) private char token() throws IOException { int ch = reader.read(); if (ch == -1) { throw new RuntimeException("Unexpected end of input"); } return (char) ch; } // 回退字符(对应C++的unget()) private void unget(char ch) throws IOException { reader.unread(ch); } public double factor() throws IOException { double val = 0; char ch = token(); if (ch == '(') { val = expression(); ch = token(); if (ch != ')') { throw new RuntimeException("Expected ')', got: " + ch); } } else if (Character.isDigit(ch)) { unget(ch); // 把数字首字符放回流 // 读取完整的数字字符串 StringBuilder numStr = new StringBuilder(); int nextCh; while ((nextCh = reader.read()) != -1) { char c = (char) nextCh; if (Character.isDigit(c) || c == '.') { numStr.append(c); } else { unget(c); // 把非数字字符放回 break; } } val = Double.parseDouble(numStr.toString()); } else { throw new RuntimeException("Unexpected character: " + ch); } return val; } public double term() throws IOException { double val = factor(); char ch = token(); if (ch == '*' || ch == '/') { double b = term(); val = ch == '*' ? val * b : val / b; } else { unget(ch); // 放回非操作符字符 } return val; } public double expression() throws IOException { double val = term(); char ch = token(); if (ch == '+' || ch == '-') { double b = expression(); val = ch == '+' ? val + b : val - b; } else { unget(ch); // 放回非操作符字符 } return val; } public static void main(String[] args) throws IOException { ExpressionParser parser = new ExpressionParser("(5+6-(6*2)/3)"); System.out.println(parser.expression()); // 输出7.0 } }
方案2:字符数组+指针(更适合字符串输入)
如果你的输入是字符串而非流,更简单的方式是把整个输入转成字符数组,用一个指针记录当前读取位置,“回退”操作直接把指针减1即可,完全不需要IO处理:
public class ExpressionParser { private final char[] input; private int pos = 0; public ExpressionParser(String input) { this.input = input.toCharArray(); } // 读取下一个字符 private char token() { if (pos >= input.length) { throw new RuntimeException("Unexpected end of input"); } return input[pos++]; } // 回退操作(指针减1) private void unget() { if (pos > 0) { pos--; } } public double factor() { double val = 0; char ch = token(); if (ch == '(') { val = expression(); ch = token(); if (ch != ')') { throw new RuntimeException("Expected ')', got: " + ch); } } else if (Character.isDigit(ch)) { unget(); // 指针回退,重新读取完整数字 StringBuilder numStr = new StringBuilder(); while (pos < input.length && (Character.isDigit(input[pos]) || input[pos] == '.')) { numStr.append(input[pos++]); } val = Double.parseDouble(numStr.toString()); } else { throw new RuntimeException("Unexpected character: " + ch); } return val; } public double term() { double val = factor(); char ch = token(); if (ch == '*' || ch == '/') { double b = term(); val = ch == '*' ? val * b : val / b; } else { unget(); // 指针回退 } return val; } public double expression() { double val = term(); char ch = token(); if (ch == '+' || ch == '-') { double b = expression(); val = ch == '+' ? val + b : val - b; } else { unget(); // 指针回退 } return val; } public static void main(String[] args) { ExpressionParser parser = new ExpressionParser("(5+6-(6*2)/3)"); System.out.println(parser.expression()); // 输出7.0 } }
方案选择建议
- 如果输入来自文件/网络流,用
PushbackReader更合适,能直接处理流输入; - 如果输入是字符串(比如表达式解析场景),字符数组+指针的方式更高效,还能避免IO异常处理,代码更简洁。
内容的提问来源于stack exchange,提问作者Dihan
相关产品推荐
相关产品推荐

