2016-03-09 2 views
3

У меня есть следующие Стингконвертировать строки CSV в список объектов

const string csv = "Foo1,Foo2,Foo3,Foo4,Foo5,Foo6,Ping Pong\n" + 
        "2016-02-29,1437.530029,1445.839966,1433.77002,1436.930054,34016300,1436.930054\n" + 
        "2016-02-25,1431.439941,1431.439941,1421.280029,1426.97998,78076500,1426.97998\n" + 
        "2016-02-24,1430.459961,1432.430054,1417.449951,1419.790039,29049900,1419.790039\n"; 

Как я могу преобразовать его в List<Model> где

public class Model 
{ 
    public string Foo1 { get; set; } 
    public string Foo2 { get; set; } 
    public string Foo3 { get; set; } 
    public string Foo4 { get; set; } 
    public string Foo5 { get; set; } 
    public string Foo6 { get; set; } 
    public string Ping_Pong { get; set; } 
} 

Примечание заголовка Ping Pong в моей ориг CSV

Я попытался использовать CsvHelper, но без успеха, поскольку он принимает стрелу я, а затем строка, и я потерпел неудачу, пытаясь преобразовать синтаксические

EDIT Это не имеет значения для меня, если использовать CsvHelper или нет, в конце концов, я хочу, чтобы преобразовать CSV в List<Model>

Как я могу сделай это?

+0

Почему вы не реализовать пользовательскую логику разбора здесь? –

+0

Или вы можете легко преобразовать строку в поток: var ms = new MemoryStream (новый UTF8Encoding.GetBytes (csv)); – Kevin

+0

Есть способы конвертировать 'string' в' Stream' http: // stackoverflow.com/questions/1879395/how-to-generate-a-stream-from-a-string – juharr

ответ

8

Вы можете создать StringReader используя csv переменную:

var textReader = new StringReader(csv); 

var csvr = new CsvReader(textReader); 
var records = csvr.GetRecords<Model>(); 

Если вы хотите, чтобы ваш собственный парсер:

var lines = csv.Split(new char[] {'\n'}, StringSplitOptions.RemoveEmptyEntries).Skip(1); 
List<Model> models = new List<Model>(); 

foreach (var item in lines) 
{ 
    var values = item.Split(','); 
    var model = new Model 
    { 
     Foo1 = values[0], 
     Foo2 = values[1], 
     Foo3 = values[2], 
     Foo4 = values[3], 
     Foo5 = values[4], 
     Foo6 = values[5], 
     Ping_Pong = values[6], 
    }; 

    models.Add(model); 
} 

EDIT:

Для повторного решить проблему заголовка с помощью CsvHelper вам необходимо создать класс конфигурации карту с указанием, как это отображения между заголовками и свойствами:

public class ModelMap : CsvClassMap<Model> 
{ 
    public ModelMap() 
    { 
     Map(m => m.Foo1); 
     Map(m => m.Foo2); 
     Map(m => m.Foo3); 
     Map(m => m.Foo4); 
     Map(m => m.Foo5); 
     Map(m => m.Foo6); 
     Map(m => m.Ping_Pong).Name("Ping Pong"); 
    } 
} 

Использование так:

var textReader = new StringReader(csv); 

var csvr = new CsvReader(textReader); 
csvr.Configuration.RegisterClassMap<ModelMap>(); 

var records = csvr.GetRecords<Model>(); 
+0

Это прекрасно работает, мой вопрос в том, как я могу присвоить заголовок правильному свойству в классе Model? Я предпочитаю вместо чтения [x] место – user829174

+0

@ user829174: обновленный ответ –

+0

Вы можете просто выполнить 'csv.Split ('\ n')' используя разделители 'Split (params char []), поскольку вы не действительно нужно удалить пустые записи для примера OP. – juharr

0

Чтобы сделать именно то, что вы просили, вы можете использовать это:

var modelStrings = csv.Split('\n').Skip(1); 
var models = new List<Model>(); 
foreach(string s in modelStrings) 
{ 
    var props = s.Split(','); 
    models.Add(new Model(props[0],props[1],props[2],props[3],props[4],props[5],props[6])); 

} 

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

Edit:

Чтобы выяснить, что это делает, это первый разбивает строку CSV на новых линиях пропуске первый. Затем он использует каждую строку в этом списке и разбивает их запятыми, чтобы получить список значений (свойств модели) для создания экземпляра класса модели с

+0

не уверен, что он будет работать, что такое «foreach (string s in models)»? – user829174

+0

whoops я изменил имя переменной, позвольте мне отредактировать мой ответ –

+0

Ваш первый раскол также разделился бы на пространство в «Ping Pong». – juharr

0

Проблема в том, что ваш набор данных (строка csv) отсутствует столбец (вы указываете 7 столбцов, но столбец Ping Pong отсутствует в csv). Поведение по умолчанию будет бросать, но вы можете установить опции конфигурации, чтобы игнорировать недостающие столбцы:

Вот рабочий код:

var config = new CsvConfiguration(); 
// setting this will cause the missing Ping Pong field to be ignored 
config.WillThrowOnMissingField = false; 

// we wrap your string in a StringReader to make it accessible to CsvReader 
var reader = new CsvReader(new StringReader(csv), config); 
var records = reader.GetRecords<Model>().ToList(); 
records.Dump(); 
+0

У меня есть данные «Ping Pong», я удвоил свой вопрос. У меня 7 значений в заголовке (где пинг-понг имеет промежуток между пробелами) и 7 значений в данных – user829174

+0

@ user829174 Вы правы, я ошибся. Я переименовал ваш заголовок из «Ping Pong» в «Ping_Pong», поэтому он соответствует вашей модели, и теперь все 7 столбцов разбора – JMarsch