Parsowanie plików z ogranicznikiem pól. Metoda String.Split i String.SplitWithCheckSeparator

Metoda Split dzieli łańcuch znaków na części w zależności od separatora, który został przekazany w parametrach. Ostatnio jednak natknąłem się na plik CSV, który oprócz tego, że jest rozdzielony przecinkami to na dodatek ma jeszcze ogranicznik pól. Parsowanie takiego pliku metodą String.Split nie będzie prawidłowe. Poniżej implementacja metody String.Split z możliwością zdefiniowania ogranicznika pól(checkSeparator).

Co to jest ograniczki pól(checkSeparator)?

No taki przykład pliku CSV:

„02”,”1914751733″,5000,”97150010701010702019430000″,”ALA KOWALSKA, UL. GRUNWALDZKA 56/6 09-100 PŁOŃSK”,”001001148908″,”Spłata karty kredytowej”

Wiersz rozdzielony jest przecinkami(separator) a niektóre pola mają cudzysłów(checkSeparator) aby można było w danym polu zastosować znak separatora czyli w tym przypadku przecinek.

Zadanie polega na tym aby sparsować plik po przecinkach i nie uwzględniać tych co są miedzy cudzysłowami.

Metoda split działa tak jak się spodziewamy, dzieli string na tablicę stringów po żądanym separatorze. Do tego dochodzi parę przeciążeń, które generalnie robią to samo.

Jaka jest implementacja metody String.Spit?

Ciężko to znaleźć, myślałem, że w kodach od .NET Core-a to będzie ale chyba JESZCZE nie ma i być może będzie wnioskuje to na podstawie komentarza w tych miejscu https://github.com/dotnet/corefx/blob/6b2deeede6f9921718cd012e009764c6f4194363/src/System.Runtime/tests/System/String.Split.cs

Tak czy inaczej, zrobiłem własną implementacje metody String.Spit i do tego dodałem możliwość sparametryzowania ogranicznika(checkSeparator).

Poniżej:

public static string[] SplitWithCheckSeparator(this string line, char separator, char checkSeparator, bool eraseCheckSeparator)
{
     var separatorsIndexes = new List<int>();

     var open = false;

     for (var i = 0; i < line.Length; i++)
     {
        if (line[i] == checkSeparator)
        {
            open = !open;
        }

         if (!open && line[i] == separator)
         {
            separatorsIndexes.Add(i);
         }
      }

     separatorsIndexes.Add(line.Length);

     var result = new string[separatorsIndexes.Count];

     var first = 0;

     for (var j = 0; j < separatorsIndexes.Count; j++)
     {
        var tempLine = line.Substring(first, separatorsIndexes[j] - first);

        result[j] = eraseCheckSeparator ? tempLine.Replace(checkSeparator, ' ').Trim() : tempLine;

        first = separatorsIndexes[j] + 1;
     }

    return result;
}

 

Algorytm jest prosty, najpierw przechodzimy po całym stringu i ustalmy gdzie znajdują się przecinki rozdzielające. Nie bierzemy pod uwagę tych separatorów, które są pomiędzy ogranicznikami. Po przeleceniu całego stringu na podstawie indeksów wykorzystujemy metodę Substring aby wycinać kolejne części pomiędzy przecinkami.

Dodatkowo może jeszcze usunąć ograniczniki(checkSeparator) w zależności od parametru eraseCheckSeparator

Metodę można ulepszyć i zoptymalizować (usunąć metodę String.Replace) ale na ten moment to wystarczy.

Kody źródłowe dostępne tutaj

 https://github.com/przemekwa/ProgramingStudy/blob/master/ProgramingStudy/Study/ExtensionStringMethods.cs

Testy do metody dostępne tutaj

https://github.com/przemekwa/ProgramingStudy/blob/master/TestObject/ExtensionStringTest.cs

3 przemyślenia nt. „Parsowanie plików z ogranicznikiem pól. Metoda String.Split i String.SplitWithCheckSeparator

  1. Pingback: dotnetomaniak.pl
    1. Super, dzięki za info. Dobrze jest wiedzieć, że taka biblioteka istnieje : )

Możliwość komentowania jest wyłączona.