큰 문자열에서 인용된 개행 문자를 찾기 위해 Regex를 찾고 있습니다(C#의 경우).
문제
C# 코드에서 구문 분석해야 하는 큰 문자열(CSV 파일이라고 부르겠습니다. 실제로는 아니지만 지금은 더 쉬울 것임)이 있습니다.
구문 분석 프로세스의 첫 번째 단계는 다음을 사용하여 파일을 개별 줄로 분할합니다. StreamReader
객체와 호출 ReadLine
파일을 통해서일 때까지.그러나 특정 행에는 줄 바꿈이 포함된 따옴표(작은따옴표) 리터럴이 포함될 수 있습니다.파일을 줄 배열로 분할할 때까지 해당 개행 문자를 찾아 일시적으로 다른 종류의 토큰이나 이스케이프 시퀀스로 변환해야 합니다. 그런 다음 다시 변경할 수 있습니다.
입력 데이터 예시:
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
인용된 섹션을 찾고 그 안에서 개행 문자를 찾으려면 Regex가 더 나은 선택이 될 수 있다고 생각합니다(예: 이제 두 가지 문제가 생겼습니다)
해결책
이것은 실제 CSV 파일이 아니기 때문에 어떤 종류의 스키마가 있습니까?
귀하의 예를 보면 다음과 같습니다.int, int, int, int, 문자열, 부울, 부울, 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'");
극단적인 경우와 두 가지 문제가 있을 수 있지만 대부분의 경우에는 괜찮을 것이라고 생각합니다.Regex가 수행하는 작업은 먼저 사이에 이 있는 작은따옴표 쌍을 찾아 그 사이의 텍스트를 유지하는 TOKEN으로 을 바꾸는 것입니다.
하지만 여전히 @bryansh가 아래에 설명한 것과 같은 상태 머신으로 갈 것입니다.