-1
votes

Erreur de format lors de la tentative d'exécution du programme

Donc, aujourd'hui, j'essayais de créer une application dans laquelle l'utilisateur entre les coordonnées de sa voiture et l'application calcule le moyen le plus simple d'atteindre une station-service avant que le réservoir de carburant ne soit épuisé. Mais lorsque je voulais tester si l'application affiche les données qui sont stockées dans un fichier .txt , j'obtiens une erreur System.FormatException que je ne peux pas résoudre. J'ai utilisé cette méthode de nombreuses fois auparavant et je ne sais pas quel est le problème ici.

L'erreur se produit à la ligne:

Nagyváros;150;30
Kisváros;250;300
TanyaBenzunkúttal;290;310
Szépváros;500;10
Alsóváros;250;0
Felsőváros;560;560
Középváros;300;300
FolyópartiVáros;380;400
HáromBenzinkutasváros;10;400
Nagyvárosbvezetőútja;380;230

Code:

int n = 10;

string[] cities = new string[n];
int[] x = new int[n];
int[] y = new int[n];
System.IO.StreamReader sr = new System.IO.StreamReader(
    @"..\..\CitiesGPS.txt", Encoding.GetEncoding(1250));
for (int i = 0; i < n; i++)
{
    string s = sr.ReadLine();
    int k = s.IndexOf(";");
    string city = s.Substring(0, k);
    cities[i] = city;
    int xcoor = int.Parse(s.Substring(k + 1));
    x[i] = xcoor;
    int k2 = s.IndexOf(";");
    int ycoor = int.Parse(s.Substring(k2 + 1));
    y[i] = ycoor;
}

sr.Close();
Console.WriteLine("Data in the file:");
for (int i = 0; i < n; i++)
{
    Console.WriteLine(cities[i] + ";" + x[i] + ";" + y[i]);
}

Les données:

int xcoor = int.Parse(s.Substring(k + 1));

Merci d'avance,

Blaise


9 commentaires

Dans quelle ligne se trouve l'erreur et comment est votre fichier .txt ?


Il peut s'agir de l'un des appels int.Parse ; difficile à dire en l'état. Utilisez un débogueur ou encapsulez le code dans un bloc try / catch et affichez l'exception (en regardant le numéro de ligne où elle a été lancée). De plus, sans aucun rapport, il serait possible d'utiliser plus facilement string.Split() (ou même une bibliothèque CSV) pour analyser les lignes.


L'erreur apparaît à la ligne: int xcoor = int.Parse (s.Substring (k + 1));


Supprimé Parse et les a remplacés par "Convert.ToInt32" mais cela ne fonctionne toujours pas.


docs.microsoft.com/en-us/dotnet/api/… indique qu'une exception FormatException peut se produire lorsque la chaîne d'entrée n'est pas au format correct. Donc vraisemblablement, tout s.Substring(k + 1) que s.Substring(k + 1) n'est pas un entier valide. Utilisez votre débogueur pour découvrir ce que cette expression produit réellement. Nous ne pouvons pas vous le dire car nous ne pouvons voir aucune des données que vous utilisez.


Ajout des données à la question.


PS Pourquoi n'utilisez-vous pas simplement une bibliothèque d'analyse CSV? (Malgré la "virgule" dans le nom CSV, en fait, toutes les bibliothèques populaires vous permettent de remplacer n'importe quel délimiteur, par exemple ; dans votre cas, et toujours lire le fichier.)


Merci pour les données. Maintenant, en utilisant cela, un simple test vous permet de voir quel sera le problème: dotnetfiddle.net/zIPLnQ .


Aussi int k2 = s.IndexOf(";"); va juste vous obtenir le même index de ; que vous avez trouvé pour k . Pour que cela fonctionne, vous devez regarder uniquement à l'intérieur de la sous-chaîne à partir de l'occurrence du premier point-virgule.


3 Réponses :


1
votes

Vous n'avez aucune longueur sur l'appel Substring du milieu, il prend donc le reste de la ligne.

for (int i = 0; i < n; i++)
{
    var parts = sr.ReadLine().Split(";");
    string city = parts[0];
    cities[i] = city;
    int xcoor = int.Parse(parts[1]);
    x[i] = xcoor;
    int k2 = s.IndexOf(";");
    int ycoor = int.Parse(parts[2]);
    y[i] = ycoor;
}

Mais, veuillez utiliser un analyseur CSV. Il n'y a aucune raison de réinventer la roue chaque fois que vous en avez besoin.

EDIT Je viens de remarquer que vous obtenez le même index de ";" en k et k2, donc cela ne fonctionnera pas du tout. Encore une fois, utilisez un analyseur CSV.

EDIT 2 Si vous n'utilisez pas d'analyseur CSV, voici une solution avec Split comme @ADyson le suggère:

int xcoor = int.Parse(s.Substring(k + 1, /* missing length*/));


3 commentaires

Quand j'ai ajouté la longueur - utilisé 0 pour que tout soit affiché - le problème s'est toujours produit mais quand j'ai changé 0 en 1, cela a commencé à fonctionner mais cela a gâché les données: /


Substring(x, y) signifie: "Prendre y caractères de la chaîne commençant à x". Bien sûr, ni 0 ni 1 ne fonctionnent.


@ FábiánBalázs pourquoi changeriez-vous la longueur en 1? Ça n'a aucun sens. Aucun de vos nombres ne comporte 1 caractère. Vous auriez besoin de faire de la longueur la distance entre le premier; et le deuxième ;. Ou faites simplement la chose sensée et utilisez string.Split !! docs.microsoft.com/en-us/dotnet/api/…



0
votes

L'échec est avec la sous-chaîne dans la ligne

var indexes = Regex.Matches(s, ";").Cast<Match>().Select(m => m.Index).ToList();
var city = s.Substring(0,indexes[0]);
var xcoor = s.Substring(indexes[0]+1,(indexes[1]-indexes[0])-1);
var ycoor = s.Substring(indexes[1]+1, (s.Length-indexes[1])-1);
cities[i] = city;
x[i] = int.Parse(xcoor);
y[i] = int.Parse(ycoor);

Vous essayez d'analyser pour int la valeur 150;30 . Et évidemment, il ne peut pas être analysé comme un nombre.

Je recommande de split chaque ligne par ; pour obtenir les valeurs de chaque position.

Vous pouvez le faire à l'intérieur for boucle for :

string[] line = s.Split(";");
var city = line[0];
var xcoor = int.Parse(line[1]);
var ycoor = int.Parse(line[2]);
cities[i] = city;
x[i] = xcoor;
y[i] = ycoor;

Modifiez pour ajouter comment cela fonctionne en utilisant substring() .

La méthode de sous- chaîne prend deux arguments:

1er: est la position de départ.
2e: Combien de postes voulez-vous obtenir.

Donc, la solution est d'obtenir l'ondex de tous ; (J'ai utilisé une expression lambda ), puis utilisez la substring de manière correcte.

C'est-à-dire: dire au programme de commencer là où un point-virgule a été trouvé et de terminer autant de positions qu'il y en a jusqu'au point-virgule suivant.

int xcoor = int.Parse(s.Substring(k + 1));

Avec ce code, vous pouvez voir la position par où commencer et «couper» la sous-chaîne.


0 commentaires

1
votes

Outre le conseil général d'utiliser un analyseur de fichiers CSV / délimités prêt à l'emploi pour cette tâche, votre propre code complique massivement le problème et souffre de diverses failles logiques lorsque vous essayez de détecter l'emplacement des délimiteurs et de calculer le les longueurs correctes des cordes entre elles.

Il est beaucoup plus simple d'utiliser simplement la méthode String.Split .

De plus, votre structure de données (composée de tableaux séparés pour les villes, les coordonnées x et les coordonnées y) n'a pas beaucoup de sens si vous avez l'intention de faire correspondre les coordonnées aux noms d'emplacement - si vous voulez faire cela, gardez les données ensemble. Une structure d'objet simple faciliterait le travail avec plus tard. Et les listes sont généralement plus faciles à utiliser que les tableaux.

Aussi pour plus de simplicité, vous devez simplement lire jusqu'à la fin du fichier, pas un nombre spécifique de lignes.

Enfin, la meilleure pratique avec un élément jetable comme un StreamReader consiste à l'initialiser en conjonction avec un bloc using pour s'assurer qu'il est correctement éliminé par la suite (voir les exemples de documentation StreamReader .

par exemple

using (System.IO.StreamReader sr = new new System.IO.StreamReader(@"..\..\CitiesGPS.txt", Encoding.GetEncoding(1250)))
{
  List<LocationData> locationList = new List<LocationData>();

  while ((s = sr.ReadLine()) != null)
  {
    string[] data = s.Split(';');
    LocationData loc = new LocationData()
    {
      Name = data[0],
      X = int.Parse(data[1]),
      Y = int.Parse(data[2])
    };
    locationList.Add(loc);
  }
}

foreach (LocationData loc in locationList)
{
    Console.WriteLine(loc.Name + ";" + loc.X + ";" + loc.Y);
}

puis

public class LocationData
{
  public string Name {get; set;}
  public int X {get; set;}
  public int Y {get; set;}
}

PS Démo super simple du traitement d'une seule ligne à l'aide de string.split: https://dotnetfiddle.net/vGXu2O


0 commentaires