Как разбить csv, чьи столбцы могут содержать,
Учитывая
2,1016,7/31/2008 14: 22, Джефф Далгас, 6/5/2011 22:21, /qaru.site/..., "Корваллис, ИЛИ", 7679,351,81, b437f461b3fd27387c5d8ab47a293d35,34
Как использовать С# для разделения приведенной выше информации на строки следующим образом:
2
1016
7/31/2008 14:22
Geoff Dalgas
6/5/2011 22:21
http://qaru.site/
Corvallis, OR
7679
351
81
b437f461b3fd27387c5d8ab47a293d35
34
Как вы видите, один из столбцов содержит, <= (Corvallis, OR)
//обновить//
Основано на
С# Regex Split - запятые вне кавычек
string[] result = Regex.Split(samplestring, ",(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)");
Ответы
Ответ 1
Используйте класс Microsoft.VisualBasic.FileIO.TextFieldParser
. Это будет обрабатывать разбор файла с разделителями, TextReader
или Stream
, где некоторые поля заключены в кавычки, а некоторые - нет.
Например:
using Microsoft.VisualBasic.FileIO;
string csv = "2,1016,7/31/2008 14:22,Geoff Dalgas,6/5/2011 22:21,http://stackoverflow.com,\"Corvallis, OR\",7679,351,81,b437f461b3fd27387c5d8ab47a293d35,34";
TextFieldParser parser = new TextFieldParser(new StringReader(csv));
// You can also read from a file
// TextFieldParser parser = new TextFieldParser("mycsvfile.csv");
parser.HasFieldsEnclosedInQuotes = true;
parser.SetDelimiters(",");
string[] fields;
while (!parser.EndOfData)
{
fields = parser.ReadFields();
foreach (string field in fields)
{
Console.WriteLine(field);
}
}
parser.Close();
Это должно привести к следующему выводу:
2
1016
7/31/2008 14:22
Geoff Dalgas
6/5/2011 22:21
http://stackoverflow.com
Corvallis, OR
7679
351
81
b437f461b3fd27387c5d8ab47a293d35
34
Подробнее см. Microsoft.VisualBasic.FileIO.TextFieldParser.
Вам нужно добавить ссылку на Microsoft.VisualBasic
на вкладке Добавить ссылки .NET.
Ответ 2
Уже так поздно, но это может быть полезно для кого-то. Мы можем использовать RegEx как ниже.
Regex CSVParser = new Regex(",(?=(?:[^\"]*\"[^\"]*\")*(?![^\"]*\"))");
String[] Fields = CSVParser.Split(Test);
Ответ 3
Вы можете разделить на все запятые, у которых есть четное число кавычек, следующих за ними.
Вы также хотели бы посмотреть на specf
для формата CSV для обработки запятой.
Полезная ссылка: C# Regex Split - commas outside quotes
Ответ 4
Используйте библиотеку, например LumenWorks, чтобы выполнить чтение CSV. Он будет обрабатывать поля с кавычками в них и, скорее всего, в целом будет более надежным, чем ваше пользовательское решение, поскольку он существует долгое время.
Ответ 5
Я вижу, что если вы вставляете csv-разделительный текст в Excel и выполняете "Text to Columns", он запрашивает у вас "текстовый определитель". Он по умолчанию имеет двойную кавычку, так что он обрабатывает текст в двойных кавычках как литерал. Я полагаю, что Excel реализует это, перейдя по одному символу за раз, если он встречает "классификатор текста", он продолжает переходить к следующему "определителю". Вы, вероятно, можете реализовать это самостоятельно с помощью цикла for и логического значения, чтобы обозначить, если вы находитесь в буквальном тексте.
public string[] CsvParser(string csvText)
{
List<string> tokens = new List<string>();
int last = -1;
int current = 0;
bool inText = false;
while(current < csvText.Length)
{
switch(csvText[current])
{
case '"':
inText = !inText; break;
case ',':
if (!inText)
{
tokens.Add(csvText.Substring(last + 1, (current - last)).Trim(' ', ','));
last = current;
}
break;
default:
break;
}
current++;
}
if (last != csvText.Length - 1)
{
tokens.Add(csvText.Substring(last+1).Trim());
}
return tokens.ToArray();
}
Ответ 6
Весьма сложно проанализировать файлы .csv, когда файл .csv может быть разделен запятыми, строками, разделенными запятыми, или хаотичной комбинацией этих двух. Решение, которое я придумал, позволяет использовать любую из трех возможностей.
Я создал метод ParseCsvRow(), который возвращает массив из строки csv. Сначала я использую двойные кавычки в строке, разделив строку на двойные кавычки на массив с именем quotesArray. Строковые. CSV файлы действительны только в том случае, если существует четное число двойных кавычек. Двойные кавычки в значении столбца следует заменить на пару двойных кавычек (это подход Excel). Пока CSV файл соответствует этим требованиям, вы можете ожидать, что разделители-разделители появятся только за пределами пар двойных кавычек. Запятые внутри пар двойных кавычек являются частью значения столбца и должны игнорироваться при расщеплении .csv в массив.
Мой метод будет проверять запятые вне пар двойных кавычек, просматривая только четные индексы quotesArray. Он также удаляет двойные кавычки из значений начала и конца столбца.
public static string[] ParseCsvRow(string csvrow)
{
const string obscureCharacter = "ᖳ";
if (csvrow.Contains(obscureCharacter)) throw new Exception("Error: csv row may not contain the " + obscureCharacter + " character");
var unicodeSeparatedString = "";
var quotesArray = csvrow.Split('"'); // Split string on double quote character
if (quotesArray.Length > 1)
{
for (var i = 0; i < quotesArray.Length; i++)
{
// CSV must use double quotes to represent a quote inside a quoted cell
// Quotes must be paired up
// Test if a comma lays outside a pair of quotes. If so, replace the comma with an obscure unicode character
if (Math.Round(Math.Round((decimal) i/2)*2) == i)
{
var s = quotesArray[i].Trim();
switch (s)
{
case ",":
quotesArray[i] = obscureCharacter; // Change quoted comma seperated string to quoted "obscure character" seperated string
break;
}
}
// Build string and Replace quotes where quotes were expected.
unicodeSeparatedString += (i > 0 ? "\"" : "") + quotesArray[i].Trim();
}
}
else
{
// String does not have any pairs of double quotes. It should be safe to just replace the commas with the obscure character
unicodeSeparatedString = csvrow.Replace(",", obscureCharacter);
}
var csvRowArray = unicodeSeparatedString.Split(obscureCharacter[0]);
for (var i = 0; i < csvRowArray.Length; i++)
{
var s = csvRowArray[i].Trim();
if (s.StartsWith("\"") && s.EndsWith("\""))
{
csvRowArray[i] = s.Length > 2 ? s.Substring(1, s.Length - 2) : ""; // Remove start and end quotes.
}
}
return csvRowArray;
}
Единственным недостатком моего подхода является то, что я временно заменяю запятые разделителем неясным символом юникода. Этот персонаж должен быть таким неясным, он никогда не появится в вашем CSV файле. Возможно, вы захотите сделать больше обработки.
Ответ 7
У меня возникла проблема с CSV, которая содержит поля с символом кавычки в них, поэтому, используя TextFieldParser, я придумал следующее:
private static string[] parseCSVLine(string csvLine)
{
using (TextFieldParser TFP = new TextFieldParser(new MemoryStream(Encoding.UTF8.GetBytes(csvLine))))
{
TFP.HasFieldsEnclosedInQuotes = true;
TFP.SetDelimiters(",");
try
{
return TFP.ReadFields();
}
catch (MalformedLineException)
{
StringBuilder m_sbLine = new StringBuilder();
for (int i = 0; i < TFP.ErrorLine.Length; i++)
{
if (i > 0 && TFP.ErrorLine[i]== '"' &&(TFP.ErrorLine[i + 1] != ',' && TFP.ErrorLine[i - 1] != ','))
m_sbLine.Append("\"\"");
else
m_sbLine.Append(TFP.ErrorLine[i]);
}
return parseCSVLine(m_sbLine.ToString());
}
}
}
StreamReader по-прежнему используется для чтения CSV по строкам, как показано ниже:
using(StreamReader SR = new StreamReader(FileName))
{
while (SR.Peek() >-1)
myStringArray = parseCSVLine(SR.ReadLine());
}
Ответ 8
С Cinchoo ETL - библиотекой с открытым исходным кодом, она может автоматически обрабатывать значения столбцов, содержащие разделители.
string csv = @"2,1016,7/31/2008 14:22,Geoff Dalgas,6/5/2011 22:21,http://stackoverflow.com,""Corvallis, OR"",7679,351,81,b437f461b3fd27387c5d8ab47a293d35,34";
using (var p = ChoCSVReader.LoadText(csv)
)
{
Console.WriteLine(p.Dump());
}
Выход:
Key: Column1 [Type: String]
Value: 2
Key: Column2 [Type: String]
Value: 1016
Key: Column3 [Type: String]
Value: 7/31/2008 14:22
Key: Column4 [Type: String]
Value: Geoff Dalgas
Key: Column5 [Type: String]
Value: 6/5/2011 22:21
Key: Column6 [Type: String]
Value: http://stackoverflow.com
Key: Column7 [Type: String]
Value: Corvallis, OR
Key: Column8 [Type: String]
Value: 7679
Key: Column9 [Type: String]
Value: 351
Key: Column10 [Type: String]
Value: 81
Key: Column11 [Type: String]
Value: b437f461b3fd27387c5d8ab47a293d35
Key: Column12 [Type: String]
Value: 34
Для получения дополнительной информации, пожалуйста, посетите статью codeproject.
Надеюсь, поможет.
Ответ 9
"Test1 Real Estate Investment Trust" ("TEst1 REIT??", код акции: 1426) - это инвестиционный траст в сфере недвижимости, который инвестирует в высококачественную доходную недвижимость. Test1 REIT, зарегистрированная 5 декабря 2013 года на фондовой бирже xyz abc, является первым xyz abc REIT, предложившим прямое подключение к двум офисным зданиям премиум-класса, стратегически расположенным в Центральном деловом районе ("CBD??") компании. предложить Unitholders стабильные дистрибуции и потенциал для устойчивого долгосрочного роста за счет инвестиций в диверсифицированный портфель приносящей доход недвижимости по всему миру. Test1 REIT управляется Test1 Asset Management Limited ("Менеджер??"), компания, зарегистрированная в xyz abc и на 90,2% принадлежит 123 Investment Co., Limited (ранее известной как 45 Capital Co., Ltd., название изменено с 1 января 2016 года), которая является инвестиционной фирмой в области прямых инвестиций, котирующейся на фондовой бирже jkl (код акции).: 7190)
Здесь я могу видеть нечетное количество цитат в строке, и это создает некоторые проблемы при сопоставлении с Regex.