1

我正在尝试使以下算法起作用。我想要做的是将给定的字符串拆分为由一系列数字或运算符组成的子字符串。

所以对于这个字符串 =“22+2”,我会得到一个数组,其中 [0]="22" [1]="+" 和 [2]="2"。

这是我到目前为止所拥有的,但是我得到了一个索引超出范围的异常:

public static void main(String[] args) {
    String string = "114+034556-2";
    int k,a,j;
    k=0;a=0;j=0;
    String[] subStrings= new String[string.length()];

    while(k<string.length()){
        a=k;
        while(((int)string.charAt(k))<=57&&((int)string.charAt(k))>=48){
            k++;}
        subStrings[j]=String.valueOf(string.subSequence(a,k-1)); //exception here

        j++;
        subStrings[j]=String.valueOf(string.charAt(k));
        j++;

   }}

我宁愿被告知我的推理出了什么问题,也不愿被提供替代方案,但我当然会感谢任何形式的帮助。

4

5 回答 5

2

我故意不直接回答这个问题,因为看起来您正在尝试自己找出解决方案。我还假设您故意不使用 split 或 indexOf 函数,这会使这非常简单。

我注意到的几件事:

  1. 如果您的输入字符串很长,您最好使用 char 数组和字符串生成器,这样可以避免不可变字符串引起的内存问题
  2. 您是否尝试过捕获异常,或打印出导致索引越界问题的 k 值?
  3. 你有没有想过当你的字符串终止时会发生什么?例如,当输入字符串是“454”或类似的微不足道的东西时,您是否通过调试器运行它?
于 2013-10-08T00:37:12.310 回答
1

您可以使用正则表达式从使用前瞻和后瞻断言的运算符中拆分数字

String equation = "22+2";
String[] tmp = equation.split("(?=[+\\-/])|(?<=[+\\-/])");
System.out.println(Arrays.toString(tmp));
于 2013-10-08T00:35:45.083 回答
0

如果您的标准只是“任何不是数字的东西”,那么如果您不介意使用并行数组,则可以使用一些简单的正则表达式 -

String[] operands = string.split("\\D");\\split around anything that is NOT a number
char[] operators = string.replaceAll("\\d", "").toCharArray();\\replace all numbers with "" and turn into char array.
于 2013-10-08T00:35:22.770 回答
0
String input="22+2-3*212/21+23";
     String number="";
     String op="";
     List<String> numbers=new ArrayList<String>();
     List<String> operators=new ArrayList<String>();
     for(int i=0;i<input.length();i++){
         char c=input.charAt(i);
         if(i==input.length()-1){
             number+=String.valueOf(c);
             numbers.add(number);
         }else if(Character.isDigit(c)){
             number+=String.valueOf(c);
         }else{
              if(c=='+' || c=='-' || c=='*' ||c=='/'){
             op=String.valueOf(c);
             operators.add(op);
             numbers.add(number);
             op="";
             number="";
             }
         }
     }
     for(String x:numbers){
         System.out.println("number="+x+",");
     }
     for(String x:operators){
         System.out.println("operators="+x+",");
     }

这将是输出 number=22,number=2,number=3,number=212,number=21,number=23,operator=+,operator=-,operator=*,operator=/,operator=+,

于 2013-10-08T00:41:27.117 回答
0

如果您对解析的一般问题感兴趣,那么我建议您逐个字符地考虑它,并使用每个新字符通过一个有限状态机。(通常您需要一个不能出现在输入中的终止符——例如 C 字符串中的 \0——但我们可以绕过它。)。

在这种情况下,您可能有以下状态:

  1. 初始状态
  2. 刚刚解析了一个数字。
  3. 刚刚解析了一个运算符。

字符确定从状态到状态的转换:

  • 您从状态 1 开始。
  • 数字转换到状态 2。
  • 操作员转换到状态 3。

当前状态可以用类似的东西来跟踪,enum在每个字符被消耗后改变状态。

使用该设置,您只需要遍历输入字符串并打开当前状态。

// this is pseudocode -- does not compile.
List<String> parse(String inputString) {
    State state = INIT_STATE;
    String curr = "";
    List<String> subStrs = new ArrayList<String>();
    for(Char c : inputString) {
      State next;
      if (isAnumber(c)) {
        next = JUST_NUM;
      } else {
        next = JUST_OP;
      }

      if (state == next) {
        // no state change, just add to accumulator:
        acc = acc + c;
      } else {
        // state change, so save and reset the accumulator:
        subStrs.add(acc);
        acc = "";
      }
      // update the state
      state = next;
    }
    return subStrs;
}

使用这样的结构,您可以通过添加新状态并根据当前状态和传入字符更新行为来更轻松地添加新功能/构造。例如,您可以添加检查以在字符串中出现字母时抛出错误(并包括偏移位置,如果您想跟踪它)。

于 2013-10-08T00:46:34.390 回答