#c#
#c#
Вопрос:
Я стремлюсь прочитать файл csv в моем методе c #. этот csv-файл не определен и может содержать n столбцов. Одна вещь, которая всегда будет оставаться постоянной, это то, что в csv-файле будет только две строки. одна будет строкой заголовка, а другая — строкой значения. Мой метод, приведенный ниже, отлично работает, когда мои значения являются строковыми значениями, но терпит неудачу, когда одно из моих значений является чем-то вроде этого [test, test1, test2]. Я пытался использовать вспомогательный класс Csv, но не могу этого сделать. может кто-нибудь подсказать мне, как мне следует подойти?
метаданные — это список строк, которые я читаю из StreamReader
private void AddValuesToTable( DynamicTableEntity tableEntry, List<string> metadata )
{
var headers = metadata[0].Split( "," );
var values = metadata[1].Split( "," );
for( int i = 0; i < headers.Count(); i )
{
tableEntry.Properties.Add( headers[i].ToString(), EntityProperty.CreateEntityPropertyFromObject( values[i] ) );
}
}
Примерное значение:
columnA,columnB,columnC
valA,[testa,testb],valc
Комментарии:
1. Ваш вопрос кажется немного расплывчатым. Какой тип значений приводит к сбою вашего метода? Вы всегда намерены использовать 2 значения, разделенные запятыми
metadata[1]
?2. Когда ваше поле содержит разделитель — поле в CSV-файле должно быть «квалифицированным», в основном заключенным в квоты — kb.blackbaud.com/knowledgebase/Article/75155 . Похоже, что для уточнения в вашем csv используются символы ‘[‘ и ‘]’. Библиотека CSVHelper позволяет вам устанавливать квалификатор — искать конфигурацию. Поле кавычек (по умолчанию это двойные квоты)
3. я обновил вопрос значением выборки, когда он не удался
4.
[
и]
разрешены ли они внутри значения? Если да, то как вы избегаете их, чтобы отличать от тех, которые используются для цитирования полей?5. вот что я не могу этого сделать .. вот где я терплю неудачу
Ответ №1:
Это код, который я использую для синтаксического анализа строки CSV.
private static string Peek(this string source, int peek) => (source == null || peek < 0) ? null : source.Substring(0, source.Length < peek ? source.Length : peek);
private static (string, string) Pop(this string source, int pop) => (source == null || pop < 0) ? (null, source) : (source.Substring(0, source.Length < pop ? source.Length : pop), source.Length < pop ? String.Empty : source.Substring(pop));
public static string[] ParseCsvLine(this string line)
{
return ParseCsvLineImpl(line).ToArray();
IEnumerable<string> ParseCsvLineImpl(string l)
{
string remainder = line;
string field;
while (remainder.Peek(1) != "")
{
(field, remainder) = ParseField(remainder);
yield return field;
}
}
}
private const string DQ = """;
private static (string field, string remainder) ParseField(string line)
{
if (line.Peek(1) == DQ)
{
var (_, split) = line.Pop(1);
return ParseFieldQuoted(split);
}
else
{
var field = "";
var (head, tail) = line.Pop(1);
while (head != "," amp;amp; head != "")
{
field = head;
(head, tail) = tail.Pop(1);
}
return (field, tail);
}
}
private static (string field, string remainder) ParseFieldQuoted(string line)
{
var field = "";
var head = "";
var tail = line;
while (tail.Peek(1) != "" amp;amp; (tail.Peek(1) != DQ || tail.Peek(2) == DQ DQ))
{
if (tail.Peek(2) == DQ DQ)
{
(head, tail) = tail.Pop(2);
field = DQ;
}
else
{
(head, tail) = tail.Pop(1);
field = head;
}
}
if (tail.Peek(2) == DQ ",")
{
(head, tail) = tail.Pop(2);
}
else if (tail.Peek(1) == DQ)
{
(head, tail) = tail.Pop(1);
}
return (field, tail);
}
Он правильно обрабатывает поля, заключенные в кавычки.