Java中的最终字符串标记生成器错误

时间:2014-01-20 20:19:08

标签: java

我写了一些代码,其格式为“1天hh:mm:ss”。使用字符串标记生成器,我试图将字符串拆分为感兴趣的各个部分,即将1天转换为86400秒,将小时转换为分钟等等。我有一个错误达到秒,然后用我的代码返回。我无法弄清问题所在。我在周末考虑过这个问题,作为最后的手段,我决定向更广泛的社群寻求更正的帮助以及更好地改进这些代码的任何建议。

目标:读取格式为“X days hh:mm:ss”的字符串并将其转换为秒。代码如下。

这个错误我的内容如下:

   "java.util.NoSuchElementException
at java.util.StringTokenizer.nextToken(StringTokenizer.java:332)
at ReadIn.parseTime(ReadIn.java:110)
at ReadIn.main(ReadIn.java:60)"

我已经收集了它与无法解析格式的最终​​int(“ss”)值有关。我不知道为什么会这样,并且想要清楚一下我的意思我做错了。

我知道这些代码的某些部分是多余的,所以我完全开放并欢迎所有建设性的批评。

提前致谢!

 public static int parseTime(String s) {

    int days = 0;
    int hours = 0;
    int minutes = 0;
    int seconds = 0;

    try{


    StringTokenizer st = new StringTokenizer(s,": ");
    if(s.contains("day")){

            days = Integer.parseInt(st.nextToken());
            String throwAway = st.nextToken();// day
            throwAway = throwAway.substring(0, throwAway.lastIndexOf(throwAway));
            hours = Integer.parseInt(st.nextToken());
            throwAway = st.nextToken();//hours
            throwAway = throwAway.substring(0, throwAway.lastIndexOf(throwAway));
            minutes = Integer.parseInt(st.nextToken());
            throwAway = throwAway.substring(0, throwAway.lastIndexOf(throwAway));
            seconds = Integer.parseInt(st.nextToken());
            throwAway = st.nextToken(); 

        }

    }catch(NoSuchElementException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }catch(NumberFormatException e){
        e.printStackTrace();
    }

    return (days*86400 + hours*3600 + minutes*60 + seconds*1);

}

3 个答案:

答案 0 :(得分:2)

根据我的统计,你的String会产生5个令牌。你打电话nextToken() 6次。并且第6次将抛出异常。

 X days hh:mm:ss
 1  2    3  4  5

值得一提的是,无论你想对substring()的那些电话做什么......都没有按照你的想法行事。他们没有做任何事情,你可以删除它们。

最后,您只需要:

days = Integer.parseInt(st.nextToken()); // token 1
st.nextToken();// // token 2 ("days")
hours = Integer.parseInt(st.nextToken()); // token 3
minutes = Integer.parseInt(st.nextToken()); // token 4
seconds = Integer.parseInt(st.nextToken()); // token 5

不需要throwaway变量;根本没有将调用中的返回值分配给nextToken()将...扔掉它。

所有这一切,都有其他方法来解决这个问题。事实上,Javadocs for StringTokenizer州:

  

StringTokenizer是一个遗留类,出于兼容性原因而保留,尽管在新代码中不鼓励使用它。建议任何寻求此功能的人都使用String的split方法或java.util.regex包。

例如,使用正则表达式和捕获组看起来像:

final Pattern pattern = Pattern.compile("(\\d+) days (\\d\\d):(\\d\\d):(\\d\\d)");
final Matcher matcher = pattern.matcher(yourString);
if (matcher.find())
{
    days = Integer.parseInt(matcher.group(1));
    hours = Integer.parseInt(matcher.group(2));     
    minutes = Integer.parseInt(matcher.group(3));
    seconds = Integer.parseInt(matcher.group(4));
}

答案 1 :(得分:1)

有一种方法可以在一行中进行计算:

public static int parseTime(String s) {
    try {
        return (int) ((new SimpleDateFormat("yyyy-MM-dd 'days' hh:mm:ss").parse("1970-01-" + s).getTime() - new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").parse("1970-01-01 00:00:00").getTime()) / 1000);
    } catch (ParseException e) {
        throw new IllegalArgumentException();
    }
}

这是有效的,因为(令人难以置信地)SimpleDateFormat允许更多的日子比实际月份更多 - 它只会翻到下个月,例如“1970-01-32”被解析为“1970-02-01” ,并且这个天数没有限制。

由于执行此操作的时区问题,您必须减去基准日期。

答案 2 :(得分:1)

考虑简化解析逻辑:

public static int parseTime( String s ) {
    int days    = 0;
    int hours   = 0;
    int minutes = 0;
    int seconds = 0;

    try{
        s = s.replaceFirst( "\\s+days?\\s+", ":" );
        StringTokenizer st = new StringTokenizer( s, ":" );
        days    = Integer.parseInt( st.nextToken() );
        hours   = Integer.parseInt( st.nextToken() );
        minutes = Integer.parseInt( st.nextToken() );
        seconds = Integer.parseInt( st.nextToken() );

    } catch( NoSuchElementException | NumberFormatException e ) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

    return ( days*86400 + hours*3600 + minutes*60 + seconds );
}