Question

I have a string

statdata = "Health 433 (+78) Attack damage 52.3 (+3.9) Health regen. 6.95 (+0.5) Attack speed 0.64 (+3.7%) Mana 230 (+70) Armor 18 (+3.2) Mana regen. 6.9 (+0.6) Magic res. 30 (+0) Range 150 (Melee) Mov. speed 350";

and i'm using substrings and indexOf to extract the data from the string and parsing them into doubles. Here is my class:

package Engine;

import WebScraper.getWikiStats;

public class MathParse {
    public static double returnStat;
    public static int indexh;
    public static String statdata;
    public static getWikiStats getStats = new getWikiStats();
    public double stringToDouble(String s){
        s.replaceAll("[^\\d.]", ""); //Remove all characters that aren't a number or a decimal
        double d = Integer.parseInt(s);
        return d;
    }

    public double parseStatData(String stat, String champion){
        statdata = "Health 433 (+78) Attack damage 52.3 (+3.9) Health regen. 6.95 (+0.5) Attack speed 0.64 (+3.7%) Mana 230 (+70) Armor 18 (+3.2) Mana regen. 6.9 (+0.6) Magic res. 30 (+0) Range 150 (Melee) Mov. speed 350";
        System.out.println(statdata);
        if(stat.equalsIgnoreCase("health")){
            returnStat = stringToDouble(statdata.substring(statdata.indexOf("Health") + 7, 3));
        }else if(stat.equalsIgnoreCase("healthpl")){
            returnStat = stringToDouble(statdata.substring(statdata.indexOf("Health") + 10, 3));
        }else if(stat.equalsIgnoreCase("mana")){
            returnStat = stringToDouble(statdata.substring(statdata.indexOf("Mana") + 5, 3));
        }else if(stat.equalsIgnoreCase("manapl")){
            returnStat = stringToDouble(statdata.substring(statdata.indexOf("Mana") + 8, 2));
        }else if(stat.equalsIgnoreCase("healthr")){
            returnStat = stringToDouble(statdata.substring(statdata.indexOf("Health regen.") + 14, 4));
        }else if(stat.equalsIgnoreCase("healthrpl")){
            returnStat = stringToDouble(statdata.substring(statdata.indexOf("Health regen.") + 18, 10));
        }else if(stat.equalsIgnoreCase("manar")){
            returnStat = stringToDouble(statdata.substring(statdata.indexOf("Mana regen.") + 12, 4));
        }else if(stat.equalsIgnoreCase("manarpl")){
            returnStat = stringToDouble(statdata.substring(statdata.indexOf("Mana regen.") + 16, 10));
        }else if(stat.equalsIgnoreCase("range")){
            returnStat = stringToDouble(statdata.substring(statdata.indexOf("Range") + 6, 3));
        }else if(stat.equalsIgnoreCase("ad")){
            returnStat = stringToDouble(statdata.substring(statdata.indexOf("Attack damage") + 14, 5));
        }else if(stat.equalsIgnoreCase("adpl")){
            returnStat = stringToDouble(statdata.substring(statdata.indexOf("Attack damage") + 19, 8));
        }else if(stat.equalsIgnoreCase("as")){
            returnStat = stringToDouble(statdata.substring(statdata.indexOf("Attack speed") + 13, 5));
        }else if(stat.equalsIgnoreCase("aspl")){
            returnStat = stringToDouble(statdata.substring(statdata.indexOf("Attack speed") + 19, 4));
        }else if(stat.equalsIgnoreCase("armor")){
            returnStat = stringToDouble(statdata.substring(statdata.indexOf("Armor") + 6, 4));
        }else if(stat.equalsIgnoreCase("armorpl")){
            returnStat = stringToDouble(statdata.substring(statdata.indexOf("Armor") + 11, 5));
        }else if(stat.equalsIgnoreCase("mr")){
            returnStat = stringToDouble(statdata.substring(statdata.indexOf("Magic res.") + 11, 4));
        }else if(stat.equalsIgnoreCase("mrpl")){
            returnStat = stringToDouble(statdata.substring(statdata.indexOf("Magic res.") + 16, 5));
        }else if(stat.equalsIgnoreCase("ms")){
            returnStat = stringToDouble(statdata.substring(statdata.indexOf("Mov. Speed") + 11, 3));
        }else{
            returnStat = 0;
        }
        return returnStat;
    }
}

and here are the errors I get when I use the parseStatData method :

"main" java.lang.StringIndexOutOfBoundsException: String index out of range: -4
at java.lang.String.substring(Unknown Source)
at Engine.MathParse.parseStatData(MathParse.java:18)
at Champions.champTemplate.showStats(champTemplate.java:27)
at Main.TheoryCrafting.theoryLoop(TheoryCrafting.java:29)
at Main.MainClass.checkCommand(MainClass.java:32)
at Main.MainClass.start(MainClass.java:22)
at Main.MainClass.main(MainClass.java:10)

I don't know what is going wrong and I'd really appreciate help.

Was it helpful?

Solution

String#substring() is meant to throw an IndexOutOfBoundsException if the first parameter is greater than the second parameter.

Effectively, a substring intends to take the lowest start index, and work its way up to but not including the highest index value you provide it. It has a range of [a, b).

If a > b, then you would be taking a very strange range - and Java has elected to error out on that case.

The culprit(s) are [likely all of] your substring statements:

statdata.substring(statdata.indexOf("Health") + 7, 3);

Unless the index of "Health" comes out negative, you'll always be overstepping the bounds of this substring.

Perhaps you want to reverse the order instead:

statdata.substring(3, statdata.indexOf("Health") + 7);

...although, that may be a bandage solution to a larger problem - you're attempting to parse one giant string with substrings, and that's not going to be maintainable in the long run.

Two solutions - one naive, one slightly better than naive - either use a String[] or a Map<String, String> to hold your data.

Here's a solution using a Map:

Map<String, String> statData = new HashMap<>();

statData.put("Health", "433 (+78)");
statData.put("Attack damage", "52.3 (+3.9)");
// and so forth
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top