J'ai un csv, j'ai besoin de lire que dans une colonne, il contient une valeur entière, mais il y a un espace après la valeur, donc dans le csv, la valeur est "1,264 ".

Dans la classe que j'ai

public int MyValue { get; set; }

Mais lorsque j'essaye de ReadRecords, j'obtiens l'erreur suivante:

TypeConverterException: la conversion ne peut pas être effectuée. Texte: '1,264' MemberType: System.Int32 TypeConverter: 'CsvHelper.TypeConversion.Int32Converter' IReader state: ColumnCount: 0 CurrentIndex: 26 HeaderRecord:

Apparemment, j'ai besoin de réduire l'espace vide sur le terrain. Je n'ai aucun contrôle sur le format du format initial.

Je pourrais en faire une propriété de chaîne et l'analyser à un deuxième passage, mais je veux voir s'il existe un autre moyen.

MISE À JOUR

J'ai essayé de supprimer l'espace et j'ai toujours l'erreur. J'avais pensé que cela pouvait être un problème d'informations sur la culture, et lorsque je lis, j'ai le code suivant:

using (var reader = new StreamReader(@"C:\temp\file.csv"))
using (var csv = new CsvReader(reader, new CsvConfiguration(new CultureInfo("en-US")) {
    TrimOptions = TrimOptions.Trim  
})) {...}

MISE À JOUR 2

The code

Considérez un fichier contenant un en-tête avec une seule colonne et une seule ligne (en plus de l'en-tête):

MyValue 
"1,264 "

MISE À JOUR 3

Ma locale actuelle dicte que la virgule est un séparateur décimal et le point est le séparateur des milliers.

2
Giannis Paraskevopoulos 15 mars 2021 à 13:28

3 réponses

Meilleure réponse

Ainsi, comme déjà mentionné dans les commentaires 1.264 est un double et essayer de l'analyser comme un entier lèvera une exception. Et l'espace supplémentaire n'est pas un problème dans une configuration CSV par défaut:

public static class Program
{
    static void Main(string[] args)
    {
        var csvContent = @"Id,Value
1,""1.236 """;

        List<Entry> entries;

        using (var reader = new StringReader(csvContent))
        using (var csvReader = new CsvReader(reader, CultureInfo.GetCultureInfo("en-us")))
        {
            entries = csvReader.GetRecords<Entry>().ToList();
        }

        foreach (var entry in entries)
        {
            Console.WriteLine($"{entry.Id} {entry.Value}");
        }
    }
}

public class Entry
{
    public int Id { get; set; }
    public double Value { get; set; }
}
1
Oliver 15 mars 2021 à 11:03

J'ai pu résoudre le problème sans changer la déclaration int en un double en utilisant le TypeConverter

Voici les étapes:

Créez d'abord la classe de convertisseur de type

public class TestClass
{
    public int Value { get; set; }
}
public class IntegerWithGroupSeparatorConverter: CsvHelper.TypeConversion.ITypeConverter
{
    public string ConvertToString(object value, IWriterRow row, MemberMapData mpd)
    {
        return value?.ToString();
    }
    public object ConvertFromString(string text, IReaderRow row, MemberMapData memberMapData)
    {
        if(Int32.TryParse(text, NumberStyles.Any, CultureInfo.InvariantCulture, out int result))
            return result;
        else
            return 0; // Not sure if 0 is acceptable or not
    }
}
public class TestMap : ClassMap<Test>
{
    public TestMap()
    {
        Map(m => m.Value).TypeConverter<IntegerWithGroupSeparatorConverter>();
    }
}

Maintenant, nous pouvons fournir ce type de convertisseur à votre code de lecture avec ceci

List<TestClass> entries;
CultureInfo ci = new CultureInfo("en-us");
using (var reader = new StringReader(csvContent))
using (var csvReader = new CsvReader(reader, ci))
{
    csvReader.Context.RegisterClassMap<TestMap>();
    entries = csvReader.GetRecords<TestClass>().ToList();
}
1
Steve 15 mars 2021 à 11:41

J'ai fouillé dans le code source et j'ai trouvé la solution.

Si vous vérifiez la source de Int32Converter, vous peut voir, il convertit en utilisant les NumberStyles définis dans le membre en tant qu'attribut ou obtient la valeur par défaut d'entier.

Lorsque j'ai défini l'attribut NumberStyles sur Number, cela a fonctionné sans autre changement. Je préfère cette solution car je n'ai pas à changer le type attendu de propriété.

J'ai donc juste dû changer la définition de classe en:

public class TestClass
{
    [Name("MyValue"), CsvHelper.Configuration.Attributes.Optional, NumberStyles(NumberStyles.Number)]
    public int MyValue { get; set; }
}
1
Giannis Paraskevopoulos 15 mars 2021 à 11:53