Ищу регулярное выражение для поиска новых строк в кавычках в большой строке (для C #)
Вопрос
У меня есть большая строка (давайте назовем ее CSV-файлом, хотя на самом деле это не так, просто сейчас так будет проще), которую я должен разобрать в коде C #.
Первый шаг процесса синтаксического анализа разбивает файл на отдельные строки, просто используя StreamReader
объект и вызывающий ReadLine
пока это не пройдет через файл.Однако любая заданная строка может содержать заключенный в одинарные кавычки литерал со встроенными символами новой строки.Мне нужно найти эти новые строки и временно преобразовать их в какой-либо другой вид токена или escape-последовательности, пока я не разделю файл на массив строк..тогда я смогу изменить их обратно.
Пример входных данных:
1,2,10,99,'Some text without a newline', true, false, 90
2,1,11,98,'This text has an embedded newline
and continues here', true, true, 90
Я мог бы написать весь код на C #, необходимый для этого, используя string.IndexOf
чтобы найти разделы в кавычках и поискать в них новые строки, но я думаю, что регулярное выражение может быть лучшим выбором (т.Е. теперь у меня есть две проблемы)
Решение
Поскольку это не настоящий CSV-файл, есть ли у него какая-либо схема?
Из вашего примера видно, что у вас есть:int, int, int, int, строка, bool, bool, int
С учетом этого создается ваша запись / объект.
Предполагая, что ваши данные хорошо сформированы (я недостаточно знаю о вашем источнике, чтобы понять, насколько обоснованно это предположение);ты мог бы:
- Прочитай свою реплику.
- Используйте конечный автомат для анализа ваших данных.
- Если ваша строка заканчивается, и вы разбираете строку, прочитайте следующую строку ... и продолжайте разбор.
Я бы по возможности избегал использования регулярных выражений.
Другие советы
Конечные машины для выполнения такой работы упрощаются с помощью итераторов C # 2.0.Надеюсь, это последний CSV-парсер, который я когда-либо напишу.Весь файл обрабатывается как перечислимый набор перечислимых строк, т.е.строки / столбцы.IEnumerable хорош тем, что затем он может быть обработан операторами LINQ.
public class CsvParser
{
public char FieldDelimiter { get; set; }
public CsvParser()
: this(',')
{
}
public CsvParser(char fieldDelimiter)
{
FieldDelimiter = fieldDelimiter;
}
public IEnumerable<IEnumerable<string>> Parse(string text)
{
return Parse(new StringReader(text));
}
public IEnumerable<IEnumerable<string>> Parse(TextReader reader)
{
while (reader.Peek() != -1)
yield return parseLine(reader);
}
IEnumerable<string> parseLine(TextReader reader)
{
bool insideQuotes = false;
StringBuilder item = new StringBuilder();
while (reader.Peek() != -1)
{
char ch = (char)reader.Read();
char? nextCh = reader.Peek() > -1 ? (char)reader.Peek() : (char?)null;
if (!insideQuotes && ch == FieldDelimiter)
{
yield return item.ToString();
item.Length = 0;
}
else if (!insideQuotes && ch == '\r' && nextCh == '\n') //CRLF
{
reader.Read(); // skip LF
break;
}
else if (!insideQuotes && ch == '\n') //LF for *nix-style line endings
break;
else if (ch == '"' && nextCh == '"') // escaped quotes ""
{
item.Append('"');
reader.Read(); // skip next "
}
else if (ch == '"')
insideQuotes = !insideQuotes;
else
item.Append(ch);
}
// last one
yield return item.ToString();
}
}
Обратите внимание, что файл считывается посимвольно, при этом код решает, следует ли рассматривать новые строки как разделители строк или как часть строки, заключенной в кавычки.
Что, если вы поместили весь файл в переменную, а затем разделили ее на основе новых строк без кавычек?
Редактировать: Извините, я неправильно истолковал ваш пост.Если вы ищете регулярное выражение, то вот одно из них:
content = Regex.Replace(content, "'([^']*)\n([^']*)'", "'\1TOKEN\2'");
Могут быть крайние случаи и эти две проблемы, но я думаю, что большую часть времени все должно быть в порядке.Что делает регулярное выражение, так это то, что оно сначала находит любую пару одинарных кавычек, между которыми есть , и заменяет это СИМВОЛОМ, сохраняя любой текст между ними.
Но все же, я бы использовал конечный автомат, как то, что @bryansh объяснил ниже.