views:

1962

answers:

4

I'm trying to get a line of integers from a text file and parse them into separate variables. The text file is set up like this:

ID:HP:MP:STR:WIS:SPD:GOLD:XP

0:100:50:10:5:12:5:10

I want to split them with the : symbol in between each. One of the problems I'm having with this is being able to read the file line by line as strings, parsing them, and then storing the parsed strings as ints. Here is the code I'm attempting to use so far:

class monster
{
    string line;
    string[] mstats;
    string[] mname;
    char[] delimeterChars = {':'};
    int id;
    int i = -1;
    int j = 0;
    int hp;
    int mp;
    int str;
    int wis;
    int spd;
    int gold;
    int xp;

    public monster(int id)
    {
        StreamReader stats = new StreamReader("monsterStats.txt");
        while(i != id)
        {
            i++;
            line = stats.ReadLine();
            mstats = line.Split(delimeterChars);
            j = 0;
            foreach(string s in mstats)
            {
                if (j == 0) id = int.Parse(s);
                else if (j == 1) hp = int.Parse(s);
                else if (j == 2) mp = int.Parse(s);
                else if (j == 3) str = int.Parse(s);
                else if (j == 4) wis = int.Parse(s);
                else if (j == 5) spd = int.Parse(s);
                else if (j == 6) gold = int.Parse(s);
                else if (j == 7) xp = int.Parse(s);
                j++;
            }
        }
        curHp = hp;
        curMp = mp;
        curSpd = spd;
        curStr = str;
        curWis = wis;
    }
}

I get the following error when this code runs:

Input string was not in a correct format. It references this part of the code:

if (j == 0) id = int.Parse(s);
+3  A: 

Why the foreach? How about:

id = int.Parse(mstats[0]);
hp = int.Parse(mstats[1]);

and so on. With a check beforehand that mstats is long enough.

A bit of Linq would let you get an array of integers in one shot:

int[] fields = line.Split(delimeterChars).Select(s => int.Parse(s)).ToArray();

id = field[0];
hp = field[2];

As for getting the code working, try printing out the line of text, and each piece of text just before you pass it to Parse. If it's not an integer, that's your problem.

Daniel Earwicker
+1 for simplicity. Be aware that this will throw an exception, as it should, if the column contains a non-integer value.
Dave Swersky
+1 for `String.Split` . Far superior to using a regular expression, for this input. Also for suggesting printing out the text to see what is wrong. Obvious but important.
Brian
+3  A: 

Well, the first thing is to find out what the bad input was.

If you're expecting bad input data, use int.TryParse instead of just int.Parse. If you're not expecting bad input data, the fact that it's throwing an exception is probably appropriate - but you should examine your data to find out what's wrong.

I'd also recommend putting the parsing call once rather than in every case. It's not like you're doing a different kind of parsing for each field.

Jon Skeet
+3  A: 

A very good way for parsing text input are always regular expressions.

Regex r = new Regex(@"(?<id>\d+):(?<hp>\d+):(?<mp>\d+):(?<str>\d+):(?<wis>\d+):(?<spd>\d+):(?<gold>\d+):(?<xp>\d+)");

// loop over lines
Monster m = new Monster();
Match mc = r.Match(input);

m.hp = GetValue(mc.Groups["hp"], m.hp);
m.mp = GetValue(mc.Groups["mp"], m.mp);
m.str = GetValue(mc.Groups["str"], m.str);
...


// method to handle extracted value
private static int GetValue(Group g, int fallback)
{
    if (g == null) throw new ArgumentNullException("g");
    return g.Success ? Convert.ToInt32(g.Value) : fallback;
}

The method GetValue checks the extracted value. If the match failed (perhaps "" or "AB" instead of a number - g.Success is false) you can handle it the way you want. In my way i simply use an fallback value.

http://msdn.microsoft.com/en-us/library/hs600312.aspx

michl86
don't say "always". there are exceptions. html for example.
Mark
A: 

Here's is something I have done, and the solution is eye openeing. I tried to solve codejam 10 qualification problem number 1 (the snapper one), and the solution file had size of 785MB, Mega Bytes! MEGA BYTES! Tell me what's wrong?

public void Initialize()
    {
        //Console.WriteLine("Getting number of times array initialized");
        //int NOT = GetNOT(); //NOT is Number Of Times.
        //For manual testing...
        //Console.WriteLine("Devices : ");
        //int Devices = int.Parse(Console.ReadLine());
        //Console.WriteLine("Clicks : ");
        //long Clicks = long.Parse(Console.ReadLine());
        GetReady();

    }

    private void GetReady()
    {
        string[] strs = new string[2];
        char[] delimiter = { ' ' };
        string line;
        int NOD;
        long NOC;
        int a = 0;
        //open file
        Console.WriteLine("PLease Enter the input file name");
        string input = Console.ReadLine();
        StreamReader sr = new StreamReader(input);
        Console.WriteLine("Please Enter the output file name");
        string output = Console.ReadLine();
        StreamWriter sw = new StreamWriter(output);

        StringBuilder sb = new StringBuilder();
        //line = sr.ReadLine();
        while ((line = sr.ReadLine()) != null)
        {
            strs = line.Split(delimiter);
            NOD = int.Parse(strs[0].ToString());
            NOC = int.Parse(strs[1].ToString());
            //get Number of Devices and NumOfClicks...

            Devices[] Devices_ = new Devices[NOD];
            for (int i = 0; i <= Devices_.Length - 1; i++)
            {
                Devices_[i] = new MiscConsole.Devices();
                Devices_[i].PowerIn = false;
                Devices_[i].State = false;
            }

            Devices_[0].PowerIn = true;

            bool ans = Click(Devices_, NOC,a);

            if (ans == true) sb.AppendLine("Case #" + a + ": ON");
            else sb.AppendLine("Case #" + a + ": OFF");
            sw.WriteLine(sb);
            Console.WriteLine(a + ".");
            a++;
        }
    }
    private int GetNOT()
    {
        StreamReader sr = new StreamReader();
        return int.Parse(sr.ReadLine());
    }

    private bool Click(Devices[] Devices_, long Clicks, int a)
    {
        int k = Devices_.Length;
        int l = Devices_.Length-1;
        for (int c = 1; c <= Clicks; c++)
        {
            for (int i = 0; i < k; i++)
            {
                if (Devices_[i].PowerIn == true) { Devices_[i].State = ChangeState(Devices_[i].State); }
            }
            for (int i = 0; i < l; i++)
            {
                if ((Devices_[i].State == true) && (Devices_[i].PowerIn == true)) Devices_[i + 1].PowerIn = true;
                else Devices_[i + 1].PowerIn = false;
            }
        }
        if (Devices_[Devices_.Length - 1].State == true) return true;
        else return false;
    }

    private bool ChangeState(bool p)
    {
        if (p == true)
            return false;
        else
            return true;

    }


}
class Devices
{
    public bool PowerIn = false;
    public bool State = false;
}

Well I tried Uploading image and it is here...

http://www.coscientech.blogspot.com/ -- Correction-- I know what's wrong. I forgot to put sb.clear(); After that every thing is fine.

Anubhav Saini