2009-03-21 11 views
2

J'essaie d'obtenir une ligne d'entiers à partir d'un fichier texte et de les analyser en variables séparées. Le fichier texte est configuré comme ceci:Lecture et analyse d'entiers à partir d'un fichier texte

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

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

Je veux les séparer avec: le symbole entre chaque. L'un des problèmes que j'ai avec cela est de pouvoir lire le fichier ligne par ligne en tant que chaînes, en les analysant, puis en stockant les chaînes analysées en tant qu'ints. Voici le code que je tente d'utiliser jusqu'à présent:

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; 
    } 
} 

Je reçois l'erreur suivante lorsque ce code fonctionne:

chaîne d'entrée était pas dans un format correct. Il fait référence à cette partie du code:

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

Wow, je viens de réaliser que j'avais la « clé » en haut du fichier texte avec l'ID: HP: MP ... a tout chambouler lol. Complètement oublié qu'il était là-haut. Merci pour tous les conseils sur le nettoyage du code tout le monde! Premier utilisateur ici, je reviendrai quand j'aurai d'autres questions! –

+1

Oh mec, j'ai réfléchi en demandant si cette ligne d'en-tête était dans le fichier mais j'ai pensé: "Naaah ... ne peut pas être ça!" :) –

Répondre

3

Pourquoi foreach? Que diriez-vous:

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

et ainsi de suite. Avec un contrôle préalable, mstats est assez long.

Un peu de Linq vous permettrait d'obtenir un tableau d'entiers en un seul coup:

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

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

Comme pour obtenir le code de travail, essayez d'imprimer la ligne de texte, et chaque morceau de texte juste avant passez-le à Parse. Si ce n'est pas un nombre entier, c'est votre problème.

+0

+1 pour plus de simplicité.Sachez que cela lèvera une exception, comme il se doit, si la colonne contient une valeur non entière. –

+0

+1 pour 'String.Split'. Très supérieur à l'utilisation d'une expression régulière, pour cette entrée. Aussi pour avoir suggéré d'imprimer le texte pour voir ce qui ne va pas. Évident mais important. – Brian

3

Eh bien, la première chose est de savoir ce que l'entrée était mauvaise.

Si vous attend mauvaises données d'entrée, utilisez int.TryParse au lieu de simplement int.Parse. Si vous êtes et non en attendant de mauvaises données d'entrée, le fait qu'il lève une exception est probablement approprié - mais vous devriez examiner vos données pour trouver ce qui ne va pas.

Je recommande également de mettre l'appel d'analyse une fois plutôt que dans tous les cas. Ce n'est pas comme si vous faisiez un type différent d'analyse pour chaque champ.

2

Un très bon moyen d'analyser la saisie de texte est toujours une expression régulière.

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; 
} 

La méthode GetValue vérifie la valeur extraite. Si la correspondance a échoué (peut-être "" ou "AB" au lieu d'un nombre - g.Success est faux), vous pouvez le gérer comme vous le souhaitez. À ma manière, j'utilise simplement une valeur de repli.

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

+0

ne dites pas "toujours". il y a des exceptions. html par exemple. – mpen

Questions connexes