Gérer les virgules dans un fichier CSV

472

Je recherche des suggestions sur la façon de gérer un fichier csv qui est créé, puis téléchargé par nos clients, et qui peut avoir une virgule dans une valeur, comme un nom d'entreprise.

Certaines des idées que nous examinons sont les suivantes: identificateurs cités (valeur "," valeurs "," etc.) ou en utilisant un | au lieu d'une virgule. Le plus gros problème est que nous devons faciliter les choses, sinon le client ne le fera pas.

Bob le concierge
la source
le client l'écrit et le télécharge
Bob The Janitor
1
Voici la solution pour gérer les commos internes dans un fichier csv. visitez stackoverflow.com/questions/9889225/…
Hasan Abrar
sur iOS, vous devez essentiellement utiliser github.com/Flinesoft/CSVImporter
Fattie
3
Notez que ce QA est ancien. De nos jours, csv signifie RFC 4180 et c'est tout.
Fattie
J'ai exactement le même problème, en essayant de totaliser une colonne dans un fichier csv qui est séparé par des virgules. Aucun problème avec une commande awk. Malheureusement, certaines cellules peuvent contenir des virgules (dans une adresse par exemple), d'autres non. Vous recherchez une solution compatible Linux mais vous ne savez pas par où commencer.
greenage

Réponses:

223

Comme d'autres l'ont dit, vous devez échapper les valeurs qui incluent des guillemets. Voici un petit lecteur CSV en C♯ qui prend en charge les valeurs entre guillemets, y compris les guillemets intégrés et les retours chariot.

Soit dit en passant, il s'agit d'un code testé à l'unité. Je le poste maintenant parce que cette question semble se poser beaucoup et que d'autres ne voudront peut-être pas une bibliothèque entière lorsque le simple support CSV fera l'affaire.

Vous pouvez l'utiliser comme suit:

using System;
public class test
{
    public static void Main()
    {
        using ( CsvReader reader = new CsvReader( "data.csv" ) )
        {
            foreach( string[] values in reader.RowEnumerator )
            {
                Console.WriteLine( "Row {0} has {1} values.", reader.RowIndex, values.Length );
            }
        }
        Console.ReadLine();
    }
}

Voici les cours. Notez que vous pouvez également utiliser la Csv.Escapefonction pour écrire un CSV valide.

using System.IO;
using System.Text.RegularExpressions;

public sealed class CsvReader : System.IDisposable
{
    public CsvReader( string fileName ) : this( new FileStream( fileName, FileMode.Open, FileAccess.Read ) )
    {
    }

    public CsvReader( Stream stream )
    {
        __reader = new StreamReader( stream );
    }

    public System.Collections.IEnumerable RowEnumerator
    {
        get {
            if ( null == __reader )
                throw new System.ApplicationException( "I can't start reading without CSV input." );

            __rowno = 0;
            string sLine;
            string sNextLine;

            while ( null != ( sLine = __reader.ReadLine() ) )
            {
                while ( rexRunOnLine.IsMatch( sLine ) && null != ( sNextLine = __reader.ReadLine() ) )
                    sLine += "\n" + sNextLine;

                __rowno++;
                string[] values = rexCsvSplitter.Split( sLine );

                for ( int i = 0; i < values.Length; i++ )
                    values[i] = Csv.Unescape( values[i] );

                yield return values;
            }

            __reader.Close();
        }
    }

    public long RowIndex { get { return __rowno; } }

    public void Dispose()
    {
        if ( null != __reader ) __reader.Dispose();
    }

    //============================================


    private long __rowno = 0;
    private TextReader __reader;
    private static Regex rexCsvSplitter = new Regex( @",(?=(?:[^""]*""[^""]*"")*(?![^""]*""))" );
    private static Regex rexRunOnLine = new Regex( @"^[^""]*(?:""[^""]*""[^""]*)*""[^""]*$" );
}

public static class Csv
{
    public static string Escape( string s )
    {
        if ( s.Contains( QUOTE ) )
            s = s.Replace( QUOTE, ESCAPED_QUOTE );

        if ( s.IndexOfAny( CHARACTERS_THAT_MUST_BE_QUOTED ) > -1 )
            s = QUOTE + s + QUOTE;

        return s;
    }

    public static string Unescape( string s )
    {
        if ( s.StartsWith( QUOTE ) && s.EndsWith( QUOTE ) )
        {
            s = s.Substring( 1, s.Length - 2 );

            if ( s.Contains( ESCAPED_QUOTE ) )
                s = s.Replace( ESCAPED_QUOTE, QUOTE );
        }

        return s;
    }


    private const string QUOTE = "\"";
    private const string ESCAPED_QUOTE = "\"\"";
    private static char[] CHARACTERS_THAT_MUST_BE_QUOTED = { ',', '"', '\n' };
}
harpo
la source
2
Vous devrez peut-être également traduire \ r \ n pour la conformité de Windows, en fonction de votre application.
Mandrake
3
@NadaNaeem, voulez-vous élaborer?
harpo
il ne compte pas correctement les éléments d'une ligne de fichier csv, il ne gère pas bien les virgules dans les champs et les retours de courage et de
tapotements
-1 OP ne spécifie pas une langue qui crée le fichier. Si un autre programmeur vient ici à la recherche d'une solution dans un langage autre que C #, il ne trouvera pas de solution à utiliser dans cette réponse.
Ben Leggiero
8
@ BenC.R.Leggiero, alors je suppose que vous devez également voter contre la question, car elle est sans réponse selon votre norme. En l'état, le code équivaut à une implémentation formelle d'une spécification simple et peut facilement être traduit dans n'importe quel langage couramment utilisé.
harpo
395

Pour 2017, csv est entièrement spécifié - RFC 4180.

C'est une spécification très courante, et est complètement couverte par de nombreuses bibliothèques ( exemple ).

Utilisez simplement n'importe quelle bibliothèque csv facilement accessible , c'est-à-dire RFC 4180.


Il y a en fait une spécification pour le format CSV et comment gérer les virgules:

Les champs contenant des sauts de ligne (CRLF), des guillemets doubles et des virgules doivent être placés entre guillemets doubles.

http://tools.ietf.org/html/rfc4180

Donc, pour avoir des valeurs fooet bar,baz, vous faites ceci:

foo,"bar,baz"

Une autre exigence importante à considérer (également de la spécification):

Si des guillemets doubles sont utilisés pour entourer des champs, un guillemet double apparaissant à l'intérieur d'un champ doit être échappé en le précédant d'un autre guillemet double. Par exemple:

"aaa","b""bb","ccc"
Corey Trager
la source
120
"Les champs contenant des sauts de ligne (CRLF), des guillemets doubles et des virgules doivent être placés entre guillemets doubles."
Eli
42
"Si des guillemets doubles sont utilisés pour entourer des champs, alors un guillemet double apparaissant à l'intérieur d'un champ doit être échappé en le précédant d'un autre guillemet double."
C. Dragon 76
11
Pas vraiment une spécification, mais toujours très pratique. Il dit ... "Il n'existe aucune spécification formelle qui permet une grande variété d'interprétations des fichiers CSV. Cette section décrit le format qui semble être suivi par la plupart des implémentations."
Justin Clarke
5
N'oubliez pas non plus que, malgré son nom, les valeurs CSV de la ligne peuvent être séparées non seulement par des virgules - du moins sur les plates-formes Windows. Cela dépend des paramètres régionaux actuels (intl.cpl en ligne de commande, « Paramètres avancés »), en particulier, séparateur de liste: System.Globalization.CultureInfo.CurrentCulture.TextInfo.ListSeparator.
lxa
4
Veuillez mettre les informations pertinentes dans cette réponse, en plus du lien, vers A) Supprimez la plupart des commentaires ci-dessus (et les miens), B) Enregistrez autant de personnes que le répondeur le temps d'aller sur une autre page et de trouver les informations pertinentes données, C) Empêcher Link Rot.
user66001
76

Le format CSV utilise des virgules pour séparer les valeurs, les valeurs qui contiennent des retours chariot, des sauts de ligne, des virgules ou des guillemets doubles sont entourées de guillemets doubles. Les valeurs qui contiennent des guillemets doubles sont citées et chaque citation littérale est échappée par une citation immédiatement précédente: Par exemple, les 3 valeurs:

test
list, of, items
"go" he said

serait codé comme suit:

test
"list, of, items"
"""go"" he said"

Tout champ peut être cité, mais seuls les champs contenant des virgules, CR / NL ou des guillemets doivent être indiqués.

Il n'y a pas de véritable standard pour le format CSV, mais presque toutes les applications suivent les conventions documentées ici . Le RFC qui a été mentionné ailleurs n'est pas une norme pour CSV, c'est un RFC pour l'utilisation de CSV dans MIME et contient des limitations non conventionnelles et inutiles qui le rendent inutile en dehors de MIME.

Un problème que de nombreux modules CSV que j'ai vus ne prennent pas en compte est le fait que plusieurs lignes peuvent être codées dans un seul champ, ce qui signifie que vous ne pouvez pas supposer que chaque ligne est un enregistrement distinct, vous devez soit ne pas autoriser les retours à la ligne dans votre données ou être prêt à gérer cela.

Robert Gamble
la source
40

Mettez des guillemets doubles autour des chaînes. C'est généralement ce que fait Excel .

Ala Eli,

vous échappez à un guillemet double comme deux guillemets doubles. Par exemple "test1", "foo" "bar", "test2"

Joe Phillips
la source
essentiellement le même concept qu'un identifiant cité
Bob The Janitor
1
vous échappez à un guillemet double comme deux guillemets doubles. Par exemple "test1", "foo" "bar", "test2"
Eli
Le simple fait de mettre des guillemets doubles autour de la chaîne ne fonctionne pas quand un "est immédiatement suivi d'une virgule
MondKin
9

Vous pouvez mettre des guillemets doubles autour des champs. Je n'aime pas cette approche, car elle ajoute un autre caractère spécial (la citation double). Définissez simplement un caractère d'échappement (généralement une barre oblique inverse) et utilisez-le partout où vous devez échapper quelque chose:

données, plus de données, plus de données \, même, encore plus

Vous n'avez pas besoin d'essayer de faire correspondre les guillemets et vous avez moins d'exceptions à analyser. Cela simplifie également votre code.

Adam Jaskiewicz
la source
3
Rapide et sale mais ne fonctionne pas si vous avez réellement une entrée contenant "\",
Sarp Kaya
1
Sarp, c'est pourquoi un double \\ est une barre oblique inversée, car cela devient maintenant un autre caractère spécial.
Grungondola
1
Cela fonctionne, mais n'est pas CSV. C'est un DSV .
TRiG
8

Il existe une bibliothèque disponible via nuget pour gérer à peu près n'importe quel CSV bien formé (.net) - CsvHelper

Exemple pour mapper à une classe:

var csv = new CsvReader( textReader );
var records = csv.GetRecords<MyClass>();

Exemple de lecture de champs individuels:

var csv = new CsvReader( textReader );
while( csv.Read() )
{
    var intField = csv.GetField<int>( 0 );
    var stringField = csv.GetField<string>( 1 );
    var boolField = csv.GetField<bool>( "HeaderName" );
}

Laisser le client gérer le format de fichier:
, est le délimiteur de champ standard, "est la valeur standard utilisée pour échapper les champs qui contiennent un délimiteur, un guillemet ou une fin de ligne.

Pour utiliser (par exemple) #des champs et 'des échappements:

var csv = new CsvReader( textReader );
csv.Configuration.Delimiter = "#";
csv.Configuration.Quote = ''';
// read the file however meets your needs

Plus de documentation

NikolaiDante
la source
3
Il serait préférable que vous incluiez un exemple d'utilisation de la CsvHelperbibliothèque pour résoudre le problème de l'OP.
George Stocker
Pourquoi presque tout dans .Net doit-il être un "assistant" ... le mot n'a presque aucun sens ... comme "Manager".
bytedev
5

Comme mentionné dans mon commentaire à la réponse de harpo, sa solution est bonne et fonctionne dans la plupart des cas, mais dans certains cas, lorsque les virgules sont directement adjacentes, elles ne se divisent pas sur les virgules.

Cela est dû au fait que la chaîne Regex se comporte de manière inattendue en tant que chaîne vertabim. Pour que ce comportement soit correct, tous les "caractères de la chaîne d'expression régulière doivent être échappés manuellement sans utiliser l'échappement vertabim.

C'est à dire. Le regex devrait être ceci en utilisant des échappements manuels:

",(?=(?:[^\"\"]*\"\"[^\"\"]*\"\")*(?![^\"\"]*\"\"))"

ce qui se traduit par ",(?=(?:[^""]*""[^""]*"")*(?![^""]*""))"

Lorsque vous utilisez une chaîne vertabim, @",(?=(?:[^""]*""[^""]*"")*(?![^""]*""))"elle se comporte comme suit, comme vous pouvez le voir si vous déboguez l'expression régulière:

",(?=(?:[^"]*"[^"]*")*(?![^"]*"))"

Donc en résumé, je recommande la solution de harpo, mais attention à ce petit piège!

J'ai inclus dans le CsvReader un petit coffre-fort facultatif pour vous informer si cette erreur se produit (si vous avez un nombre pré-connu de colonnes):

if (_expectedDataLength > 0 && values.Length != _expectedDataLength) 
throw new DataLengthException(string.Format("Expected {0} columns when splitting csv, got {1}", _expectedDataLength, values.Length));

Cela peut être injecté via le constructeur:

public CsvReader(string fileName, int expectedDataLength = 0) : this(new FileStream(fileName, FileMode.Open, FileAccess.Read))
{
    _expectedDataLength = expectedDataLength;
}
MikeDub
la source
Comment feriez-vous pour gérer la ligne d'en-tête? j'essaie de mapper le csv aux objets C # qui sont de tous types, mais la ligne d'en-tête le casse parce que ce sont toutes des chaînes ...
tCoe
N'est-ce pas [^""]la même chose que [^"]? La duplication d'un caractère dans une spécification de classe de caractères est redondante, non?
Minh Tran
4

Ajoutez une référence à Microsoft.VisualBasic (oui, il dit VisualBasic mais cela fonctionne aussi bien en C # - rappelez-vous qu'à la fin, tout est juste IL).

Utilisez la Microsoft.VisualBasic.FileIO.TextFieldParserclasse pour analyser le fichier CSV Voici l'exemple de code:

 Dim parser As TextFieldParser = New TextFieldParser("C:\mar0112.csv")
 parser.TextFieldType = FieldType.Delimited
 parser.SetDelimiters(",")      

   While Not parser.EndOfData         
      'Processing row             
      Dim fields() As String = parser.ReadFields         
      For Each field As String In fields             
         'TODO: Process field                   

      Next      
      parser.Close()
   End While 
mvilaskumar
la source
Oui, c'est une classe très utile dans un espace de noms quelque peu malheureux ;-). Pour répondre à la question d'origine, cependant, vous devez également définir parser.HasFieldsEnclosedInQuotes = true;et le fichier d'entrée devrait inclure des champs contenant des virgules entre guillemets selon la spécification CSV - Excel le fait déjà.
Christopher King,
4

Si vous êtes sur un nix-système * , avoir accès à sedet il peut y avoir un ou plusieurs virgules indésirables que dans un champ spécifique de votre CSV, vous pouvez utiliser la seule ligne suivante afin de les enfermer dans "de RFC4180 Section 2 propose:

sed -r 's/([^,]*,[^,]*,[^,]*,)(.*)(,.*,.*)/\1"\2"\3/' inputfile

Selon le champ dans lequel les virgules indésirables peuvent se trouver, vous devez modifier / étendre les groupes de capture de l'expression régulière (et la substitution).
L'exemple ci-dessus mettra le quatrième champ (sur six) entre guillemets.

entrez la description de l'image ici

En combinaison avec l' --in-placeoption vous pouvez appliquer ces modifications directement au fichier.

Afin de "construire" la bonne expression rationnelle, il y a un principe simple à suivre:

  1. Pour chaque champ de votre CSV qui précède le champ avec la ou les virgules indésirables, vous en écrivez un [^,]*,et les rassemblez tous dans un groupe de capture.
  2. Pour le champ qui contient la ou les virgules indésirables que vous écrivez (.*).
  3. Pour chaque champ après le champ avec la ou les virgules indésirables, vous en écrivez un ,.* et les rassemblez tous dans un groupe de capture.

Voici un bref aperçu des différentes expressions rationnelles / substitutions possibles en fonction du domaine spécifique. Sinon, la substitution est \1"\2"\3.

([^,]*)(,.*)                     #first field, regex
"\1"\2                           #first field, substitution

(.*,)([^,]*)                     #last field, regex
\1"\2"                           #last field, substitution


([^,]*,)(.*)(,.*,.*,.*)          #second field (out of five fields)
([^,]*,[^,]*,)(.*)(,.*)          #third field (out of four fields)
([^,]*,[^,]*,[^,]*,)(.*)(,.*,.*) #fourth field (out of six fields)

Si vous souhaitez supprimer les virgules indésirables au sedlieu de les entourer de guillemets, reportez-vous à cette réponse .

Basti M
la source
3

Si vous avez envie de réinventer la roue, les éléments suivants peuvent vous convenir:

public static IEnumerable<string> SplitCSV(string line)
{
    var s = new StringBuilder();
    bool escaped = false, inQuotes = false;
    foreach (char c in line)
    {
        if (c == ',' && !inQuotes)
        {
            yield return s.ToString();
            s.Clear();
        }
        else if (c == '\\' && !escaped)
        {
            escaped = true;
        }
        else if (c == '"' && !escaped)
        {
            inQuotes = !inQuotes;
        }
        else
        {
            escaped = false;
            s.Append(c);
        }
    }
    yield return s.ToString();
}
Neil
la source
3

En Europe, nous avons ce problème doit plus tôt que cette question. En Europe, nous utilisons tous une virgule pour un point décimal. Voir ces chiffres ci-dessous:

| American      | Europe        |
| ------------- | ------------- |
| 0.5           | 0,5           |
| 3.14159265359 | 3,14159265359 |
| 17.54         | 17,54         |
| 175,186.15    | 175.186,15    |

Il n'est donc pas possible d'utiliser le séparateur de virgules pour les fichiers CSV. Pour cette raison, les fichiers CSV en Europe sont séparés par un point-virgule ( ;) .

Des programmes comme Microsoft Excel peuvent lire des fichiers avec un point-virgule et il est possible de passer du séparateur. Vous pouvez même utiliser un onglet ( \t) comme séparateur. Voir cette réponse de Supper User .

H. Pauwelyn
la source
2

Si vous êtes intéressé par un exercice plus éducatif sur la façon d'analyser les fichiers en général (en utilisant CSV comme exemple), vous pouvez consulter cet article de Julian Bucknall. J'aime l'article parce qu'il décompose les choses en problèmes beaucoup plus petits et beaucoup moins insurmontables. Vous créez d'abord une grammaire, et une fois que vous avez une bonne grammaire, c'est un processus relativement simple et méthodique pour convertir la grammaire en code.

L'article utilise C # et a un lien en bas pour télécharger le code.

Phil
la source
1

Voici une petite solution de contournement intéressante:

Vous pouvez utiliser un signe de chiffre inférieur grec à la place (U + 0375)

Ça ressemble à ça ͵

L'utilisation de cette méthode vous permet également d'économiser beaucoup de ressources ...

Konstantine Nikka-Sher Piterma
la source
1

Utilisez simplement SoftCircuits.CsvParser sur NuGet. Il gérera tous ces détails pour vous et gère efficacement les très gros fichiers. Et, si nécessaire, il peut même importer / exporter des objets en mappant les colonnes aux propriétés des objets. De plus, mes tests ont montré qu'il était en moyenne près de 4 fois plus rapide que le populaire CsvHelper.

Jonathan Wood
la source
0

Comme il s'agit de pratiques générales, commençons par les règles générales:

  1. N'utilisez pas CSV, utilisez XML avec une bibliothèque pour lire et écrire le fichier xml à la place.

  2. Si vous devez utiliser CSV. Faites-le correctement et utilisez une bibliothèque gratuite pour analyser et stocker les fichiers CSV.

Pour justifier 1), la plupart des analyseurs CSV ne connaissent pas le codage, donc si vous ne traitez pas avec US-ASCII, vous demandez des problèmes. Par exemple, Excel 2002 stocke le CSV dans le codage local sans aucune note sur le codage. La norme CSV n'est pas largement adoptée :(. En revanche, la norme xml est bien adoptée et elle gère assez bien les encodages.

Pour justifier 2), il y a des tonnes d'analyseurs csv pour presque toutes les langues, il n'est donc pas nécessaire de réinventer la roue même si les solutions semblent assez simples.

Pour n'en nommer que quelques-uns:

  • pour python, utilisez la construction dans le module csv

  • pour perl vérifier CPAN et Text :: CSV

  • pour php, utilisez les fonctions fgetcsv / fputcsv

  • pour la bibliothèque Java SuperCVS

Il n'est vraiment pas nécessaire de l'implémenter à la main si vous n'allez pas l'analyser sur un périphérique intégré.

Piotr Czapla
la source
12
XML n'est pas toujours la réponse. CSV est le bon format pour le travail lorsque vous avez beaucoup de données tabulaires denses (c'est-à-dire une feuille de calcul). Ces balises introduisent beaucoup de surcharge, et si chaque ligne a un format identique, il n'est pas nécessaire d'être explicite sur ce que représente chaque valeur. XML est idéal lorsque vous avez des données hiérarchiques complexes ou des enregistrements avec des champs facultatifs. Ce n'est pas toujours le cas.
Adam Jaskiewicz
En théorie, les "balises" introduisent un peu de surcharge mais je ne peux penser à aucune application réelle où cela commence à être un problème. Avez-vous des exemples pratiques? Pour travailler sur des données, il faut utiliser une base de données au lieu de csv. si nous parlons de sérialisation des données (sauvegardes, échange de données), cela importera-t-il si l'analyse prend une semaine au lieu de 5 jours?
Piotr Czapla
2
Fondamentalement, toute situation dans laquelle vous disposez de données mieux représentées par un tableau. Supposons que vous disposez de données provenant d'une douzaine de capteurs différents que vous échantillonnez de temps en temps, et que vous enregistrez l'horodatage et la valeur de chacun des capteurs à ce moment-là. Chaque enregistrement est identique: horodatage, sensor0, sensor1, ... sensor11. XML est idéal pour représenter des données complexes et irrégulières, mais c'est un format plutôt lourd qui ne convient pas à toutes les situations. KISS
Adam Jaskiewicz
10
Certaines personnes voient un problème et disent: "Je sais, je vais utiliser XML!" Maintenant, ils ont deux problèmes.
Adam Jaskiewicz
Je suis totalement d'accord que xml n'est pas une réponse à tout. Surtout, il ne convient pas comme remplacement de base de données ni pour les fichiers de configuration. Mais ici, la question portait sur l'échange de données pour lequel XML a été conçu.
Piotr Czapla
0

Vous pouvez lire le fichier csv comme ceci.

cela utilise des divisions et prend soin des espaces.

ArrayList List = new ArrayList();
static ServerSocket Server;
static Socket socket;
static ArrayList<Object> list = new ArrayList<Object>();


public static void ReadFromXcel() throws FileNotFoundException
{   
    File f = new File("Book.csv");
    Scanner in = new Scanner(f);
    int count  =0;
    String[] date;
    String[] name;
    String[] Temp = new String[10];
    String[] Temp2 = new String[10];
    String[] numbers;
    ArrayList<String[]> List = new ArrayList<String[]>();
    HashMap m = new HashMap();

         in.nextLine();
         date = in.nextLine().split(",");
         name = in.nextLine().split(",");
         numbers = in.nextLine().split(",");
         while(in.hasNext())
         {
             String[] one = in.nextLine().split(",");
             List.add(one);
         }
         int xount = 0;
         //Making sure the lines don't start with a blank
         for(int y = 0; y<= date.length-1; y++)
         {
             if(!date[y].equals(""))
             {   
                 Temp[xount] = date[y];
                 Temp2[xount] = name[y];
                 xount++;
             }
         }

         date = Temp;
         name =Temp2;
         int counter = 0;
         while(counter < List.size())
         {
             String[] list = List.get(counter);
             String sNo = list[0];
             String Surname = list[1];
             String Name = list[2];
             for(int x = 3; x < list.length; x++)
             {           
                 m.put(numbers[x], list[x]);
             }
            Object newOne = new newOne(sNo, Name, Surname, m, false);
             StudentList.add(s);
             System.out.println(s.sNo);
             counter++;
         }
Eric
la source
0

Tout d'abord, posons-nous la question: "Pourquoi ressentons-nous le besoin de gérer les virgules différemment pour les fichiers CSV?"

Pour moi, la réponse est: "Parce que lorsque j'exporte des données dans un fichier CSV, les virgules dans un champ disparaissent et mon champ est séparé en plusieurs champs où les virgules apparaissent dans les données d'origine." (C'est parce que la virgule est le caractère séparateur de champ CSV.)

Selon votre situation, des points-virgules peuvent également être utilisés comme séparateurs de champ CSV.

Compte tenu de mes besoins, je peux utiliser un caractère, par exemple, un guillemet simple bas 9, qui ressemble à une virgule.

Alors, voici comment vous pouvez le faire dans Go:

// Replace special CSV characters with single low-9 quotation mark
func Scrub(a interface{}) string {
    s := fmt.Sprint(a)
    s = strings.Replace(s, ",", "‚", -1)
    s = strings.Replace(s, ";", "‚", -1)
    return s
}

Le deuxième caractère à virgule dans la fonction Remplacer est décimal 8218.

Sachez que si vous avez des clients qui peuvent avoir des lecteurs de texte ascii uniquement, ce caractère decima 8218 ne ressemblera pas à une virgule. Si tel est votre cas, je vous recommande de entourer le champ de virgule (ou point-virgule) avec des guillemets doubles selon RFC 4128: https://tools.ietf.org/html/rfc4180

l3x
la source
0

J'encode généralement par URL les champs qui peuvent avoir des virgules ou des caractères spéciaux. Et puis le décoder lorsqu'il est utilisé / affiché sur n'importe quel support visuel.

(les virgules deviennent% 2C)

Chaque langue devrait avoir des méthodes pour encoder et décoder les chaînes URL.

par exemple, en java

URLEncoder.encode(myString,"UTF-8"); //to encode
URLDecoder.decode(myEncodedstring, "UTF-8"); //to decode

Je sais que c'est une solution très générale et qu'elle pourrait ne pas être idéale pour les situations où l'utilisateur souhaite afficher manuellement le contenu du fichier csv.

hariszhr
la source
0

Je fais généralement cela dans mes routines d'analyse de fichiers CSV. Supposons que la variable «ligne» soit une ligne dans un fichier CSV et que toutes les valeurs des colonnes soient placées entre guillemets. Après l'exécution des deux lignes ci-dessous, vous obtiendrez des colonnes CSV dans la collection «values».

// The below two lines will split the columns as well as trim the DBOULE QUOTES around values but NOT within them
    string trimmedLine = line.Trim(new char[] { '\"' });
    List<string> values = trimmedLine.Split(new string[] { "\",\"" }, StringSplitOptions.None).ToList();
user1451111
la source
1
Pourquoi mon code n'est jamais affiché en plusieurs couleurs sur StackOverflow? J'entre en retrait de quatre espaces.
user1451111
0

La solution la plus simple que j'ai trouvée est celle que LibreOffice utilise:

  1. Remplacer tous les littéraux "par
  2. Mettez des guillemets doubles autour de votre chaîne

Vous pouvez également utiliser celui qu'Excel utilise:

  1. Remplacer tous les littéraux "par""
  2. Mettez des guillemets doubles autour de votre chaîne

Remarquez que d'autres personnes ont recommandé de ne faire que l'étape 2 ci-dessus, mais cela ne fonctionne pas avec les lignes où a "est suivi de a ,, comme dans un CSV où vous voulez avoir une seule colonne avec la chaîne hello",world, comme le CSV le lirait:

"hello",world"

Qui est interprété comme une ligne avec deux colonnes: helloetworld"

MondKin
la source
1
Selon les règles standard, tout champ contenant le caractère fractionné ou la citation est entouré de guillemets et toutes les citations à l'intérieur qui sont doublées, donc il n'y a pas de problème. Votre hello",worldchamp devrait simplement être enregistré sous "hello"",world", qui peut être analysé correctement à 100%.
Nyerguds
0
    public static IEnumerable<string> LineSplitter(this string line, char 
         separator, char skip = '"')
    {
        var fieldStart = 0;
        for (var i = 0; i < line.Length; i++)
        {
            if (line[i] == separator)
            {
                yield return line.Substring(fieldStart, i - fieldStart);
                fieldStart = i + 1;
            }
            else if (i == line.Length - 1)
            {
                yield return line.Substring(fieldStart, i - fieldStart + 1);
                fieldStart = i + 1;
            }

            if (line[i] == '"')
                for (i++; i < line.Length && line[i] != skip; i++) { }
        }

        if (line[line.Length - 1] == separator)
        {
            yield return string.Empty;
        }
    }
Rajat26
la source
0

J'ai utilisé la bibliothèque Csvreader mais en utilisant cela, j'ai obtenu des données en explosant à partir de la virgule (,) dans la valeur de la colonne.

Donc, si vous souhaitez insérer des données de fichier CSV contenant des virgules (,) dans la plupart des valeurs des colonnes, vous pouvez utiliser la fonction ci-dessous. Lien auteur => https://gist.github.com/jaywilliams/385876

function csv_to_array($filename='', $delimiter=',')
{
    if(!file_exists($filename) || !is_readable($filename))
        return FALSE;

    $header = NULL;
    $data = array();
    if (($handle = fopen($filename, 'r')) !== FALSE)
    {
        while (($row = fgetcsv($handle, 1000, $delimiter)) !== FALSE)
        {
            if(!$header)
                $header = $row;
            else
                $data[] = array_combine($header, $row);
        }
        fclose($handle);
    }
    return $data;
}
Vir
la source
0

J'ai utilisé la bibliothèque papaParse pour analyser le fichier CSV et avoir les paires clé-valeur (clé / en-tête / première ligne de la valeur du fichier CSV).

voici un exemple que j'utilise:

https://codesandbox.io/embed/llqmrp96pm

il contient un fichier dummy.csv pour avoir la démo d'analyse CSV.

Je l'ai utilisé dans reactJS bien qu'il soit facile et simple à reproduire dans une application écrite dans n'importe quelle langue.

parag patel
la source
0

Un exemple peut aider à montrer comment les virgules peuvent être affichées dans un fichier .csv. Créez un fichier texte simple comme suit:

Enregistrez ce fichier texte en tant que fichier texte avec le suffixe ".csv" et ouvrez-le avec Excel 2000 à partir de Windows 10.

aa, bb, cc, d; d "Dans la présentation de la feuille de calcul, la ligne ci-dessous doit ressembler à la ligne ci-dessus, sauf que ci-dessous montre une virgule affichée au lieu d'un point-virgule entre les d." aa, bb, cc, "d, d", cela fonctionne même dans Excel

aa, bb, cc, "d, d", Cela fonctionne même dans Excel 2000 aa, bb, cc, "d, d", Cela fonctionne même dans Excel 2000 aa, bb, cc, "d, d", Cela fonctionne même dans Excel 2000

aa, bb, cc, "d, d", cela échoue dans Excel 2000 en raison de l'espace belore la 1ère citation aa, bb, cc, "d, d", cela échoue dans Excel 2000 en raison de l'espace belore la 1ère citation aa, bb, cc, "d, d", cela échoue dans Excel 2000 en raison de l'espace bélier la 1ère citation

aa, bb, cc, "d, d", Cela fonctionne même dans Excel 2000 même avec des espaces avant et après le 2ème devis. aa, bb, cc, "d, d", Cela fonctionne même dans Excel 2000 même avec des espaces avant et après le 2ème devis. aa, bb, cc, "d, d", Cela fonctionne même dans Excel 2000 même avec des espaces avant et après le 2ème devis.

Règle: Si vous souhaitez afficher une virgule dans une cellule (champ) d'un fichier .csv: "Commencez et terminez le champ par des guillemets doubles, mais évitez les espaces blancs avant le premier devis"

user1247591
la source
-1

Je pense que la solution la plus simple à ce problème est d'avoir le client pour ouvrir le csv dans Excel, puis ctrl + r pour remplacer toutes les virgules par l'identifiant que vous voulez. Ceci est très simple pour le client et ne nécessite qu'une seule modification de votre code pour lire le délimiteur de votre choix.

jamesdeath123
la source
Qui a dit qu'ils avaient Excel? En fait, qui dit que c'est même un être humain qui fait le téléchargement? ...
bytedev
-3

Utilisez un caractère de tabulation (\ t) pour séparer les champs.

Pierre
la source
4
-1 Génial jusqu'à ce que quelqu'un utilise un onglet dans sa valeur, puis revenez au problème rencontré par la personne qui pose la question. L'échange d'un caractère délimiteur pour un autre ne résoudra pas le problème.
bytedev
Absurdité. Les utilisateurs ne peuvent pas saisir d'onglets dans leur entrée de données. Dans la plupart des formulaires, cela déplace simplement le point d'entrée de données vers le champ suivant.
Pierre
6
"Les gens ne peuvent pas entrer d'onglets dans leur saisie de données" .... êtes-vous sérieux ?? A) bien sûr, une personne pourrait mettre un onglet dans un champ de saisie B) qui dit que c'est une interface graphique dont les données proviennent? C) qui dit que c'est même un humain qui entre les données?
bytedev