Postępowanie z przecinkami w pliku CSV


472

Szukam sugestii, jak obsługiwać plik csv, który jest tworzony, a następnie przesyłany przez naszych klientów, który może mieć przecinek w wartości, na przykład nazwę firmy.

Niektóre z pomysłów, na które patrzymy, to: cytowane identyfikatory (wartość „,” wartości ”,„ itd.) Lub użycie | zamiast przecinka. Największym problemem jest to, że musimy to ułatwić, inaczej klient tego nie zrobi.


klient pisze i przesyła
Bob The Janitor,

1
Oto rozwiązanie do zarządzania przecinkami w pliku csv. odwiedź stackoverflow.com/questions/9889225/…
Hasan Abrar

na iOS, zasadniczo musisz użyć github.com/Flinesoft/CSVImporter
Fattie

3
Pamiętaj, że ta kontrola jakości jest stara. Obecnie csv oznacza RFC 4180 i to wszystko.
Fattie,

Mam dokładnie ten sam problem, próbuję zsumować kolumnę w pliku csv, który jest oddzielony przecinkami. Nie ma problemu z poleceniem awk. Niestety niektóre komórki mogą zawierać przecinki (na przykład w adresie), inne nie. Szukasz rozwiązania zgodnego z systemem Linux, ale nie wiesz, od czego zacząć.
greenage

Odpowiedzi:


223

Jak powiedzieli inni, musisz uciec od wartości zawierających cudzysłowy. Oto mały czytnik CSV w C♯, który obsługuje wartości cytowane, w tym osadzone cytaty i zwroty karetki.

Nawiasem mówiąc, jest to kod testowany jednostkowo. Publikuję je teraz, ponieważ wydaje się, że to pytanie często pojawia się, a inni mogą nie chcieć całej biblioteki, jeśli wystarczy prosta obsługa CSV.

Możesz użyć tego w następujący sposób:

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

Oto zajęcia. Pamiętaj, że możesz również użyć tej Csv.Escapefunkcji do napisania prawidłowego pliku CSV.

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

2
Konieczne może być także przetłumaczenie \ r \ n zgodności systemu Windows, w zależności od aplikacji.
Mandrake

3
@NadaNaeem, chcesz opracować?
harpo

nie
zlicza

-1 OP nie określa języka tworzącego plik. Jeśli jakikolwiek inny programista przyjdzie tutaj i szuka rozwiązania w innym języku niż C #, nie znajdzie rozwiązania, którego mógłby użyć w tej odpowiedzi.
Ben Leggiero,

8
@ BenC.R. Leggiero, więc przypuszczam, że musisz również głosować za pytaniem, ponieważ nie można odpowiedzieć na to pytanie według twojego standardu. W obecnej postaci kod stanowi formalną implementację prostej specyfikacji i można go łatwo przetłumaczyć na dowolny powszechnie używany język.
harpo

395

W 2017 r. Plik csv jest w pełni określony - RFC 4180.

Jest to bardzo powszechna specyfikacja i jest całkowicie objęta wieloma bibliotekami ( przykład ).

Po prostu użyj dowolnej łatwo dostępnej biblioteki csv - to znaczy RFC 4180.


W rzeczywistości istnieje specyfikacja formatu CSV i sposobu obsługi przecinków:

Pola zawierające podział wiersza (CRLF), podwójne cudzysłowy i przecinki powinny być ujęte w cudzysłowy.

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

Tak więc, aby mieć wartości fooi bar,bazrobisz to:

foo,"bar,baz"

Kolejny ważny wymóg do rozważenia (również ze specyfikacji):

Jeśli do zamykania pól stosowane są cudzysłowy, wówczas cytat pojawiający się w polu musi być poprzedzony innym podwójnym cudzysłowem. Na przykład:

"aaa","b""bb","ccc"

120
„Pola zawierające podział wiersza (CRLF), podwójne cudzysłowy i przecinki powinny być ujęte w cudzysłowy.”
Eli

42
„Jeśli do zamykania pól stosowane są cudzysłowy, to cytat pojawiający się w polu musi być poprzedzony innym cudzysłowem”.
C. Dragon 76

11
Nie jest to specyfikacja, ale prawdopodobnie jest przydatna. Mówi ... „Nie istnieje formalna specyfikacja, która pozwala na szeroką gamę interpretacji plików CSV. W tej sekcji opisano format, który wydaje się być przestrzegany przez większość implementacji”.
Justin Clarke

5
Nie zapominaj również, że pomimo nazwy wartości CSV w wierszu mogą być oddzielone nie tylko przecinkami - przynajmniej na platformach Windows. To zależy od bieżących ustawień regionalnych (intl.cpl w wierszu polecenia „Ustawienia zaawansowane”), w szczególności, separator listy: System.Globalization.CultureInfo.CurrentCulture.TextInfo.ListSeparator.
lxa

4
Proszę podać odpowiednie informacje w tej odpowiedzi, oprócz linku, do A) Usuń większość powyższych komentarzy (i moje), B) Oszczędź o wiele więcej osób niż odpowiadający czas na przejście na kolejną stronę i znalezienie odpowiedniej dane, C) Zapobiegnij gniciu linków.
user66001

76

Format CSV używa przecinków do oddzielenia wartości, wartości zawierające znaki powrotu karetki, linie, przecinki lub podwójne cudzysłowy są otoczone podwójnymi cudzysłowami. Wartości zawierające podwójne cudzysłowy są cytowane, a każdy dosłowny cytat jest poprzedzany cytatem bezpośrednio poprzedzającym: Na przykład 3 wartości:

test
list, of, items
"go" he said

byłoby zakodowane jako:

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

Każde pole może być cytowane, ale muszą zawierać tylko pola zawierające przecinki, CR / NL lub cudzysłowy być cytowane.

Nie ma prawdziwego standardu dla formatu CSV, ale prawie wszystkie aplikacje są zgodne z konwencjami tu udokumentowanymi . RFC, o którym wspomniano w innym miejscu, nie jest standardem dla CSV, jest RFC do używania CSV w MIME i zawiera pewne niekonwencjonalne i niepotrzebne ograniczenia, które czynią go bezużytecznym poza MIME.

Problemem, którego wiele modułów CSV nie widziało, jest fakt, że wiele linii może być zakodowanych w jednym polu, co oznacza, że ​​nie możesz założyć, że każda linia jest osobnym rekordem, albo musisz nie zezwalać na nowe linie w swoim dane lub bądź przygotowany na to.


40

Umieść podwójne cudzysłowy wokół ciągów. Tak ogólnie robi Excel .

Ala Eli,

unikasz podwójnego cudzysłowu jako dwa podwójne cudzysłowy. Np. „Test1”, „foo” „bar”, „test2”


w zasadzie ta sama koncepcja, co cytowany Identyfikatory
Bob The Janitor

1
unikasz podwójnego cudzysłowu jako dwa podwójne cudzysłowy. Np. „Test1”, „foo” „bar”, „test2”
Eli

Samo umieszczenie podwójnych cudzysłowów w łańcuchu nie działa, gdy po „natychmiast następuje przecinek
MondKin,

9

Możesz wstawiać podwójne cudzysłowy wokół pól. Nie podoba mi się to podejście, ponieważ dodaje kolejną postać specjalną (podwójny cytat). Po prostu zdefiniuj znak ucieczki (zwykle ukośnik odwrotny) i użyj go tam, gdzie potrzebujesz czegoś:

dane, więcej danych, więcej danych \, nawet jeszcze więcej

Nie musisz próbować dopasowywać cytatów i masz mniej wyjątków do analizy. Upraszcza to również kod.


3
Szybkie i brudne, ale nie działa, jeśli faktycznie masz wpis zawierający „\”
Sarp Kaya

1
Sarp, dlatego podwójny \\ jest ucieczką ukośnika odwrotnego, ponieważ teraz staje się on kolejną specjalną postacią.
Grungondola,

1
To działa, ale nie jest CSV. To DSV .
TRiG

8

W bibliotece nuget dostępna jest biblioteka do obsługi praktycznie każdego poprawnie sformatowanego pliku CSV (.net) - CsvHelper

Przykład odwzorowania na klasę:

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

Przykład odczytu poszczególnych pól:

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

Pozwalanie klientowi sterować formatem pliku:
, jest standardowym separatorem pól, "jest standardową wartością używaną do zmiany znaczenia pól zawierających separator, cudzysłów lub zakończenie linii.

Aby użyć (na przykład) #do pól i 'do ucieczki:

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

Więcej dokumentacji


3
Byłoby lepiej, gdybyś podał przykład wykorzystania CsvHelperbiblioteki do rozwiązania problemu PO.
George Stocker

Dlaczego prawie wszystko w .Net musi być „pomocnikiem”… słowo jest prawie bez znaczenia… jak „menedżer”.
bytedev

5

Jak wspomniano w moim komentarzu do odpowiedzi harpo, jego rozwiązanie jest dobre i działa w większości przypadków, jednak w niektórych sytuacjach, gdy przecinki jako bezpośrednio przylegające do siebie nie dzielą się na przecinki.

Wynika to z faktu, że ciąg Regex zachowuje się nieoczekiwanie jako ciąg Vertabim. Aby uzyskać prawidłowe zachowanie, wszystkie znaki w ciągu wyrażenia regularnego muszą być poprzedzane znakami ucieczki bez użycia znaku ucieczki wertykulacji.

To znaczy. Wyrażenie regularne powinno być takie przy użyciu ręcznych zmian znaczenia:

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

co przekłada się na ",(?=(?:[^""]*""[^""]*"")*(?![^""]*""))"

Podczas korzystania z ciągu vertabim @",(?=(?:[^""]*""[^""]*"")*(?![^""]*""))"zachowuje się on w następujący sposób, jak widać po debugowaniu wyrażenia regularnego:

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

Podsumowując, polecam rozwiązanie harpo, ale uważaj na tę małą gotcha!

Dołączyłem do CsvReadera trochę opcjonalnego zabezpieczenia przed awarią, aby powiadomić cię, jeśli wystąpi ten błąd (jeśli masz wcześniej znaną liczbę kolumn):

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

Można to zrobić za pomocą konstruktora:

public CsvReader(string fileName, int expectedDataLength = 0) : this(new FileStream(fileName, FileMode.Open, FileAccess.Read))
{
    _expectedDataLength = expectedDataLength;
}

Jak zabrałbyś się do obsługi wiersza nagłówka? Próbuję odwzorować csv na obiekty C #, które są wszystkich typów, ale wiersz nagłówka psuje go, ponieważ wszystkie ciągi znaków ...
tCoe

Czy to nie [^""]to samo co [^"]? Powielanie znaku w specyfikacji klasy znaków jest zbędne, prawda?
Minh Tran

4

Dodaj odniesienie do Microsoft.VisualBasic (tak, mówi VisualBasic, ale działa również w C # - pamiętaj, że na końcu wszystko to tylko IL).

Użyj Microsoft.VisualBasic.FileIO.TextFieldParserklasy do parsowania pliku CSV Oto przykładowy kod:

 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 

Tak, jest to bardzo przydatna klasa w nieco niefortunnej przestrzeni nazw ;-). Aby odpowiedzieć na pierwotne pytanie, powinieneś jednak również ustawić, parser.HasFieldsEnclosedInQuotes = true;a plik wejściowy musiałby zawierać pola zawierające przecinki w cudzysłowach zgodnie ze specyfikacją CSV - excel już to robi.
Christopher King


4

W przypadku, gdy jesteś na * nix-system , mieć dostęp do sedi tam może być jeden lub więcej tylko w niechciane przecinki dziedzinie określonej w pliku CSV, można użyć następującego jedno-liner, aby dołączyć je "jako RFC4180 Sekcji 2 proponuje:

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

W zależności od tego, w którym polu mogą znajdować się niechciane przecinki, musisz zmienić / rozszerzyć grupy przechwytywania wyrażenia regularnego (i podstawienie).
Powyższy przykład umieści czwarte pole (spośród sześciu) w cudzysłowie.

wprowadź opis zdjęcia tutaj

W połączeniu z --in-placeopcją można zastosować te zmiany bezpośrednio do pliku.

Aby „zbudować” właściwe wyrażenie regularne, należy przestrzegać prostej zasady:

  1. Dla każdego pola w pliku CSV, które występuje przed polem z niechcianymi przecinkami, piszesz jedno [^,]*,i umieszczasz je wszystkie w grupie przechwytywania.
  2. Dla pola zawierającego niechciane przecinki, które piszesz (.*).
  3. Dla każdego pola po polu z niechcianymi przecinkami zapisujesz jedno ,.* i umieszczasz je wszystkie w grupie przechwytywania.

Oto krótki przegląd różnych możliwych wyrażeń regularnych / podstawień w zależności od konkretnego pola. Jeśli nie podano, podstawienie to \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)

Jeśli chcesz usunąć niechciane przecinki, sedzamiast umieszczać je w cudzysłowie, zapoznaj się z tą odpowiedzią .


3

Jeśli masz ochotę wymyślić koło na nowo, mogą Ci pomóc następujące rzeczy:

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

3

W Europie mamy ten problem wcześniej niż to pytanie. W Europie używamy przecinka do przecinka dziesiętnego. Zobacz te liczby poniżej:

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

Dlatego nie można użyć separatora przecinków dla plików CSV. Z tego powodu pliki CSV w Europie są oddzielone średnikiem ( ;) .

Programy takie jak Microsoft Excel mogą odczytywać pliki średnikiem i można przełączyć się z separatora. Możesz nawet użyć tab ( \t) jako separatora. Zobacz tę odpowiedź od użytkownika wieczerzy .


2

Jeśli interesuje Cię bardziej edukacyjne zadanie dotyczące ogólnej analizy plików (na przykład CSV), możesz przeczytać ten artykuł autorstwa Juliana Bucknalla. Podoba mi się ten artykuł, ponieważ dzieli on rzeczy na znacznie mniejsze problemy, które są znacznie mniej nie do pokonania. Najpierw tworzysz gramatykę, a kiedy masz dobrą gramatykę, jest to stosunkowo łatwy i metodyczny proces konwersji gramatyki na kod.

Artykuł używa C # i ma link na dole, aby pobrać kod.


1

Oto schludne małe obejście:

Zamiast tego możesz użyć greckiego dolnego znaku liczbowego (U + 0375)

Tak to wygląda ͵

Korzystanie z tej metody oszczędza również wiele zasobów ...


1

Wystarczy użyć SoftCircuits.CsvParser na NuGet. Obsługuje wszystkie te szczegóły i skutecznie obsługuje bardzo duże pliki. W razie potrzeby może nawet importować / eksportować obiekty poprzez mapowanie kolumn na właściwości obiektu. Ponadto moje testy wykazały, że jest to średnio 4 razy szybsze niż popularny CsvHelper.


0

Ponieważ chodzi o ogólne praktyki, zacznijmy od podstawowych zasad:

  1. Nie używaj CSV, zamiast tego używaj XML z biblioteką do odczytu i zapisu pliku xml.

  2. Jeśli musisz użyć CSV. Zrób to poprawnie i użyj darmowej biblioteki do parsowania i przechowywania plików CSV.

Aby uzasadnić 1), większość parserów CSV nie jest świadoma kodowania, więc jeśli nie masz do czynienia z US-ASCII, pytasz o problemy. Na przykład excel 2002 przechowuje CSV w lokalnym kodowaniu bez żadnej uwagi na temat kodowania. Standard CSV nie jest powszechnie przyjęty :(. Z drugiej strony standard xml jest dobrze przyjęty i całkiem dobrze obsługuje kodowanie.

Aby uzasadnić 2), istnieje mnóstwo parserów csv dla prawie wszystkich języków, więc nie ma potrzeby wymyślania nowego koła, nawet jeśli rozwiązania wyglądają dość prosto.

Aby wymienić tylko kilka:

  • dla Pythona użyj wbudowanego modułu csv

  • dla Perla sprawdź CPAN i Text :: CSV

  • dla php użyj wbudowanej funkcji fgetcsv / fputcsv

  • dla java sprawdź bibliotekę SuperCVS

Naprawdę nie ma potrzeby implementowania tego ręcznie, jeśli nie zamierzasz go analizować na urządzeniu osadzonym.


12
XML nie zawsze jest odpowiedzią. CSV jest właściwym formatem dla zadania, gdy masz dużo gęstych, tabelarycznych danych (np. Arkusz kalkulacyjny). Znaczniki te wprowadzają wiele narzutu, a jeśli każda linia ma identyczny format, nie trzeba jednoznacznie określać, co reprezentuje każda wartość. XML jest świetny, gdy masz skomplikowane dane hierarchiczne lub rekordy z opcjonalnymi polami. Nie zawsze tak jest.
Adam Jaskiewicz

Teoretycznie „tagi” wprowadzają trochę narzutu, ale nie mogę sobie wyobrazić żadnej aplikacji z prawdziwego życia, w której zaczynałby być problemem. Czy masz jakieś praktyczne przykłady? Do pracy na danych należy użyć bazy danych zamiast csv. jeśli mówimy o serializacji danych (kopiach zapasowych, wymianie danych), czy będzie miało znaczenie, czy parsowanie zajmie tydzień zamiast 5 dni?
Piotr Czapla,

2
Zasadniczo każda sytuacja, w której masz dane najlepiej reprezentowane przez tabelę. Załóżmy, że masz dane z kilkunastu różnych czujników, które próbujesz co jakiś czas, i zapisujesz znacznik czasu i wartość każdego z czujników w tym czasie. Każdy rekord jest identyczny: znacznik czasu, czujnik 0, czujnik 1, ... czujnik 11. XML doskonale nadaje się do reprezentowania złożonych, nieregularnych danych, ale jest to format raczej ciężki, który nie pasuje do każdej sytuacji. KISS
Adam Jaskiewicz

10
Niektórzy widzą problem i mówią „Wiem, użyję XML!” Teraz mają dwa problemy.
Adam Jaskiewicz 20.04.2009

Całkowicie się zgadzam, że xml nie jest odpowiedzią na wszystko. Szczególnie nie nadaje się do zastąpienia bazy danych ani do plików konfiguracyjnych. Ale tutaj pytanie dotyczyło wymiany danych, dla której zaprojektowano XML.
Piotr Czapla

0

Możesz odczytać plik csv w ten sposób.

wykorzystuje podział i dba o przestrzeń.

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

0

Najpierw zadajmy sobie pytanie: „Dlaczego czujemy potrzebę innego traktowania przecinków dla plików CSV?”

Dla mnie odpowiedź brzmi: „Ponieważ kiedy eksportuję dane do pliku CSV, przecinki w polu znikają, a moje pole zostaje podzielone na wiele pól, w których przecinki pojawiają się w oryginalnych danych”. (To dlatego, że przecinek jest znakiem separatora pól CSV).

W zależności od sytuacji średniki mogą być również używane jako separatory pól CSV.

Biorąc pod uwagę moje wymagania, mogę użyć znaku, np. Pojedynczego niskiego 9 cudzysłowu, który wygląda jak przecinek.

Oto, jak możesz to zrobić w 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
}

Drugi znak przecinka w funkcji zamiany to dziesiętny 8218.

Należy pamiętać, że jeśli masz klientów, którzy mogą mieć czytniki tekstu tylko ascii, ten znak decima 8218 nie będzie wyglądał jak przecinek. Jeśli tak jest w twoim przypadku, polecam otaczanie pola przecinkiem (lub średnikiem) z podwójnymi cudzysłowami zgodnie z RFC 4128: https://tools.ietf.org/html/rfc4180


0

Zazwyczaj koduję adresy URL pól, które mogą zawierać przecinki lub znaki specjalne. A następnie dekoduj go, gdy jest używany / wyświetlany na dowolnym nośniku wizualnym.

(przecinki stają się% 2C)

Każdy język powinien mieć metody kodowania i dekodowania ciągów adresów URL.

np. w java

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

Wiem, że jest to bardzo ogólne rozwiązanie i może nie być idealne w sytuacji, gdy użytkownik chce ręcznie przeglądać zawartość pliku csv.


0

Zwykle robię to w procedurach analizy plików CSV. Załóżmy, że zmienna „linia” jest jedną linią w pliku CSV, a wszystkie wartości kolumn są ujęte w podwójne cudzysłowy. Po wykonaniu dwóch poniższych wierszy otrzymasz kolumny CSV w kolekcji „wartości”.

// 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();

1
Dlaczego mój kod nigdy nie jest wyświetlany w wielu kolorach na StackOverflow? Wcięłam cztery spacje.
user1451111


0

Najprostszym rozwiązaniem, jakie znalazłem, jest to, którego używa LibreOffice:

  1. Zamień wszystkie dosłowne " na
  2. Umieść podwójne cudzysłowy wokół swojego ciągu

Możesz także użyć tego, którego używa Excel:

  1. Zamień wszystkie dosłowne " na""
  2. Umieść podwójne cudzysłowy wokół swojego ciągu

Zwróć uwagę, że innym osobom zaleca się wykonanie tylko kroku 2 powyżej, ale to nie działa z wierszami, po których "następuje a ,, np. W CSV, w którym chcesz mieć pojedynczą kolumnę z ciągiem hello",world, tak jak CSV:

"hello",world"

Który jest interpretowany jako wiersz z dwiema kolumnami: helloiworld"


1
Zgodnie ze standardowymi regułami każde pole zawierające znak podziału lub cytat jest otoczone cudzysłowami, a wszelkie cytaty wewnątrz są podwojone, więc nie ma problemu. Twoje hello",worldpole musiałoby po prostu zostać zapisane jako "hello"",world", które można poprawnie przeanalizować w 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;
        }
    }

0

Użyłem biblioteki Csvreader, ale używając tego, dostałem dane, eksplodując z przecinka (,) w wartości kolumny.

Więc jeśli chcesz wstawić dane pliku CSV, które zawierają przecinek (,) w większości wartości kolumn, możesz użyć funkcji poniżej. Link do autora => 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;
}

0

Użyłem biblioteki papaParse do przeanalizowania pliku CSV i uzyskania par klucz-wartość (klucz / nagłówek / pierwszy wiersz wartości pliku CSV).

oto przykład, którego używam:

https://codesandbox.io/embed/llqmrp96pm

ma tam plik dummy.csv, aby mieć wersję demonstracyjną CSV.

Użyłem go w ReagJS, chociaż można go łatwo replikować w aplikacji napisanej w dowolnym języku.


0

Przykład może pomóc pokazać, jak przecinki mogą być wyświetlane w pliku .csv. Utwórz prosty plik tekstowy w następujący sposób:

Zapisz ten plik tekstowy jako plik tekstowy z przyrostkiem „.csv” i otwórz go w programie Excel 2000 z systemu Windows 10.

aa, bb, cc, d; d "W prezentacji arkusza kalkulacyjnego dolna linia powinna wyglądać jak powyższa linia, z tym wyjątkiem, że poniżej pokazuje wyświetlany przecinek zamiast średnika między literami d." aa, bb, cc, „d, d”, Działa to nawet w programie Excel

aa, bb, cc, „d, d”, Działa to nawet w programie Excel 2000 aa, bb, cc, „d, d”, Działa to nawet w programie Excel 2000 aa, bb, cc, „d, d”, Działa nawet w programie Excel 2000

aa, bb, cc, „d, d”, To się nie udaje w programie Excel 2000 z powodu miejsca poniżej 1. cytatu aa, bb, cc, „d, d”, To kończy się niepowodzeniem w programie Excel 2000 z powodu miejsca poniżej 1. cytatu aa, bb, cc, „d, d”, Nie udaje się to w programie Excel 2000 z powodu spacji poniżej 1. cytatu

aa, bb, cc, „d, d”, Działa to nawet w programie Excel 2000, nawet ze spacjami przed drugim cytatem i po nim. aa, bb, cc, „d, d”, Działa to nawet w programie Excel 2000, nawet ze spacjami przed drugim cytatem i po nim. aa, bb, cc, „d, d”, Działa to nawet w programie Excel 2000, nawet ze spacjami przed drugim cytatem i po nim.

Reguła: Jeśli chcesz wyświetlać przecinek w komórce (polu) pliku .csv: „Rozpocznij i zakończ pole podwójnymi cudzysłowami, ale unikaj spacji przed pierwszym cytatem”


-1

Myślę, że najłatwiejszym rozwiązaniem tego problemu jest otwarcie klienta csv w programie Excel, a następnie naciśnięcie klawiszy Ctrl + R, aby zastąpić wszystkie przecinki dowolnym identyfikatorem. Jest to bardzo łatwe dla klienta i wymaga tylko jednej zmiany w kodzie, aby odczytać wybrany przez siebie ogranicznik.


Kto powiedział, że mają Excela? W rzeczywistości, kto twierdzi, że to nawet człowiek wykonuje przesyłanie? ...
bytedev

-3

Użyj znaku tabulacji (\ t), aby oddzielić pola.


4
-1 Świetnie, dopóki ktoś nie użyje wartości karty, a następnie wrócisz do problemu, który ma osoba zadająca pytanie. Zamiana jednego znaku separatora na inny nie rozwiąże problemu.
bytedev

Nonsens. Ludzie nie mogą wchodzić w zakładki podczas wprowadzania danych. W większości formularzy to po prostu przenosi punkt wprowadzania danych do następnego pola.
Pierre

6
„Ludzie nie mogą wchodzić w zakładki podczas wprowadzania danych”… poważnie? A) oczywiście, osoba może umieścić zakładkę w polu wprowadzania B) kto mówi, że to GUI, z którego pochodzą dane? C) kto twierdzi, że nawet człowiek wprowadza dane?
bytedev
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.