Пропустить первый символ разделения в CSV

У меня есть входной файл CSV:

 |Name|Surname|Age|
 |ABCD|DCBA|11|
 |QAZ|WSX|23|

И когда я пытаюсь загрузить файл csv в свою таблицу datagridview, у меня первый столбец пуст, потому что функция считывает первый разделенный символ |.

Как пропустить первый разделенный символ в каждой строке?

Часть кода:

file.ReadLine();
string line = "";
try
{
    while ((line = file.ReadLine()) != null)
    {
        string[] splitArray = line.Split('|');
        Listing.Add(new List(splitArray[0], splitArray[1], splitArray[2]));
        count++;
    }
}
catch
{
    MessageBox.Show("Nothing to do here...");
}
file.Close();

Избегайте использования String.Split для анализа файлов, поскольку он прерывается, если значение содержит символ |. Подумайте об использовании хорошо протестированной библиотеки CSV, например nuget.org/packages/CsvHelper

Dai 22.10.2018 19:04

Может помочь метод String.Trim (char []). Вы можете указать массив символов, который следует обрезать от начала и до конца перед выполнением разделения. docs.microsoft.com/en-us/dotnet/api/…

Wiz 22.10.2018 19:06

@Dai Я добавил пример CsvHelper к своему ответу ниже.

ugh StackExchange 22.10.2018 19:29
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
3
261
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Просто проигнорируйте первый индекс, используя splitArray[1], splitArray[2] и splitArray[3] (игнорируя splitArray[0]):

file.ReadLine();
string line = "";
try
{
    while ((line = file.ReadLine()) != null)
    {
        string[] splitArray = line.Split('|');
        Listing.Add(new List(splitArray[1], splitArray[2], splitArray[3]));
        count++;
    }
}
catch
{
    MessageBox.Show("Nothing to do here...");
}
file.Close();

Как указывали другие, почему бы не использовать CsvHelper?

Вы можете сделать это с помощью довольно простой конфигурации:

public struct Listing
{
    public string Name { get; set; }
    public string Surname { get; set; }
    public int Age { get; set; }
}

using (var file = File.OpenText("test.txt"))
{
    using (var csv = new CsvHelper.CsvReader(file))
    {
        csv.Configuration.Delimiter = "|";
        var records = csv.GetRecords<Listing>().ToList();

        foreach (var record in records)
        {
            Console.WriteLine("Name: {0}, Surname: {1}, Age: {2}", record.Name, record.Surname, record.Age);
        }
    }
}

Здесь вы можете увидеть пример вывода:

Я бы избегал использования ToList, чтобы избежать ненужного выделения памяти, и использовать Skip (1) и Take (n), чтобы сделать решение более гибким, если OP требуется для внесения некоторых изменений в фрагмент.

Kevin Avignon 22.10.2018 19:39

Поскольку данные устанавливаются из файла, я бы реорганизовал ваше решение, чтобы вместо этого использовать структуру, потому что класс не имеет поведения, а вы просто представляете данные в файле. Рефакторинг должен сделать работу немного быстрее

Kevin Avignon 22.10.2018 19:41

@KevinAvignon Я всегда фанат классов, поскольку они обычно намного более расширяемы, так как он может захотеть добавить методы в будущем, такие как свойство FullName (но я обновил код). Что касается .ToList(), я знаю, что это вызовет полное перечисление, и я делаю это только потому, что Listings изначально был списком, и я не уверен, каков его план использования. Зачем мне использовать Skip(1) или Take(n)?

ugh StackExchange 22.10.2018 19:45

в выражении LINQ Skip показывает, что вы не один из первых элементов в итерации, а Take покажет, что вам понадобятся только следующие n элементов в итерации, а остальные не имеют отношения к текущему конвейеру.

Kevin Avignon 22.10.2018 19:48

Но нам нужен первый элемент в итерации? Я не понимаю, откуда это взялось. Вы пытаетесь сказать об оптимизации (т. Е. Если мы используем Skip(1), это не вызовет ненужного выделения структуры листинга, если я не использую .ToList())?

ugh StackExchange 22.10.2018 19:48

@KevinAvignon struct в C# имеет другую семантику типа значения по сравнению с class, что означает, что struct могут быть более дорогими во время выполнения, чем class, в зависимости от сценария использования, поэтому я не согласен с вашим советом. Кроме того, struct может иметь методы, реализовывать интерфейсы, быть изменяемым и т. д. - так что сказать, что «структура не имеет поведения», просто неверно.

Dai 22.10.2018 19:58

@Dai для данного сценария, у него нет поведения, и просто наличие класса для этого набора данных не имело для меня смысла. Я знаю о различиях между классом и структурой. Но в этом случае я принимаю то, что ты сказал

Kevin Avignon 22.10.2018 20:15

@FrankerZ Я говорю, что это мог быть Listing.AddRange (splitArray.Skip (1) .Take (3)), и при итерации по записям вам не нужно выделять память перед повторением по ней, вы можете разрешить записи быть IEnumerable

Kevin Avignon 22.10.2018 20:28

Я на 100% согласен с вами, и в большинстве случаев я бы предпочел пойти с вами, но при использовании блока using() {}, если он вырывается из цикла (возможно, с оператором return в веб-API), IEnumerable терпит неудачу, поскольку файловый поток был закрыт. Это приводит к тому, что у большинства новых пользователей возникают небольшие проблемы, поэтому я предпочитаю просто использовать .ToList() для облегчения доступа в будущем (хотя это определенно может привести к потере памяти / производительности для больших наборов данных).

ugh StackExchange 22.10.2018 20:32

@FrankerZ ваше решение работает. Осталось только поменять индекс с 1 ... 3, а не с 0. Не знаю, почему раньше не проверял :) :) Спасибо большое.

Frihu 23.10.2018 15:33

Я настоятельно рекомендую вам изучить csvhelper @Frihu, так как он намного лучше и дает более чистый код. (Для этого вы должны создавать структуры / классы, а не просто использовать массив)

ugh StackExchange 23.10.2018 15:35

@FrankerZ, этот csvhelper будет более эффективным, чем этот обходной путь? Что со временем конвертации файлов csv будет меньше?

Frihu 23.10.2018 18:16

Вы можете передать дополнительный второй аргумент StringSplitOptions в RemoveEmptyEntries:

string[] splitArray = line.Split('|', StringSplitOptions.RemoveEmptyEntries);

(Не DV), но это может вызвать некоторые проблемы, если одно из полей действительно содержит пустую запись. (например, |ABCD||11|)

ugh StackExchange 22.10.2018 19:07

Другие вопросы по теме