728x90
반응형
728x170
▶ CSVParser.cs
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
namespace TestProject
{
/// <summary>
/// CSV 파서
/// </summary>
public static class CSVParser
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Static
//////////////////////////////////////////////////////////////////////////////// Public
#region 파싱하기 - Parse(reader, delimiter, qualifier)
/// <summary>
/// 파싱하기
/// </summary>
/// <param name="reader">텍스트 리더</param>
/// <param name="delimiter">구분자</param>
/// <param name="qualifier">품질 구분자</param>
/// <returns>문자열 리스트 열거 가능형</returns>
public static IEnumerable<IList<string>> Parse(TextReader reader, char delimiter, char qualifier)
{
bool inQuote = false;
List<string> recordList = new List<string>();
StringBuilder stringBuilder = new StringBuilder();
while(reader.Peek() != -1)
{
char characterRead = (char)reader.Read();
if(characterRead == '\n' || (characterRead == '\r' && (char) reader.Peek() == '\n'))
{
if(characterRead == '\r')
{
reader.Read();
}
if(inQuote)
{
if(characterRead == '\r')
{
stringBuilder.Append('\r');
}
stringBuilder.Append('\n');
}
else
{
if(recordList.Count > 0 || stringBuilder.Length > 0)
{
recordList.Add(stringBuilder.ToString());
stringBuilder.Clear();
}
if(recordList.Count > 0)
{
yield return recordList;
}
recordList = new List<string>(recordList.Count);
}
}
else if(stringBuilder.Length == 0 && !inQuote)
{
if(characterRead == qualifier)
{
inQuote = true;
}
else if(characterRead == delimiter)
{
recordList.Add(stringBuilder.ToString());
stringBuilder.Clear();
}
else if(char.IsWhiteSpace(characterRead))
{
}
else
{
stringBuilder.Append(characterRead);
}
}
else if(characterRead == delimiter)
{
if (inQuote)
{
stringBuilder.Append(delimiter);
}
else
{
recordList.Add(stringBuilder.ToString());
stringBuilder.Clear();
}
}
else if(characterRead == qualifier)
{
if(inQuote)
{
if((char) reader.Peek() == qualifier)
{
reader.Read();
stringBuilder.Append(qualifier);
}
else
{
inQuote = false;
}
}
else
{
stringBuilder.Append(characterRead);
}
}
else
{
stringBuilder.Append(characterRead);
}
}
if(recordList.Count > 0 || stringBuilder.Length > 0)
{
recordList.Add(stringBuilder.ToString());
}
if(recordList.Count > 0)
{
yield return recordList;
}
}
#endregion
#region 머리말/꼬리말 파싱하기 - ParseHeadAndTail(reader, delimiter, qualifier)
/// <summary>
/// 머리말/꼬리말 파싱하기
/// </summary>
/// <param name="reader">텍스트 리더</param>
/// <param name="delimiter">구분자</param>
/// <param name="qualifier">품질 구분자</param>
/// <returns>(문자열 리스트, 문자열 리스트 열거 가능형) 튜플</returns>
public static Tuple<IList<string>, IEnumerable<IList<string>>> ParseHeadAndTail(TextReader reader, char delimiter, char qualifier)
{
return ParseHeadAndTail(Parse(reader, delimiter, qualifier));
}
#endregion
//////////////////////////////////////////////////////////////////////////////// Private
#region 꼬리말 열거하기 - EnumerateTail<T>(sourceEnumerable)
/// <summary>
/// 꼬리말 열거하기
/// </summary>
/// <typeparam name="T">타입</typeparam>
/// <param name="sourceEnumerable">소스 열거 가능형</param>
/// <returns>열거 가능형</returns>
private static IEnumerable<T> EnumerateTail<T>(IEnumerator<T> sourceEnumerable)
{
while(sourceEnumerable.MoveNext())
{
yield return sourceEnumerable.Current;
}
}
#endregion
#region 머리말/꼬리말 파싱하기 - ParseHeadAndTail<T>(sourceEnumerable)
/// <summary>
/// 머리말/꼬리말 파싱하기
/// </summary>
/// <typeparam name="T">타입</typeparam>
/// <param name="sourceEnumerable">소스 열거 가능형</param>
/// <returns>(타입, 타입 열거 가능형) 튜플</returns>
private static Tuple<T, IEnumerable<T>> ParseHeadAndTail<T>(this IEnumerable<T> sourceEnumerable)
{
if(sourceEnumerable == null)
{
throw new ArgumentNullException("sourceEnumerable");
}
IEnumerator<T> enumerator = sourceEnumerable.GetEnumerator();
enumerator.MoveNext();
return Tuple.Create(enumerator.Current, EnumerateTail(enumerator));
}
#endregion
}
}
728x90
▶ Program.cs
using System;
using System.Collections.Generic;
using System.IO;
namespace TestProject
{
/// <summary>
/// 프로그램
/// </summary>
class Program
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Static
//////////////////////////////////////////////////////////////////////////////// Private
#region 프로그램 시작하기 - Main()
/// <summary>
/// 프로그램 시작하기
/// </summary>
private static void Main()
{
string source = @"
'100','200','100','300','400'
'200','300','400','200','100'
'100','300','200','300','400'
";
using(StringReader reader = new StringReader(source))
{
IEnumerable<IList<string>> lineEnumerable = CSVParser.Parse(reader, ',', '\'');
foreach(IList<string> itemEnumerable in lineEnumerable)
{
foreach(string item in itemEnumerable)
{
Console.Write(item);
Console.Write(" ");
}
Console.WriteLine();
}
}
}
#endregion
}
}
728x90
반응형
그리드형(광고전용)
'C# > Common' 카테고리의 다른 글
[C#/COMMON] IP 주소 문자열에서 long 타입 정수 구하기 (0) | 2021.08.22 |
---|---|
[C#/COMMON] Console 클래스 : Write 정적 메소드를 사용해 마지막 문자 지우기 (0) | 2021.08.22 |
[C#/COMMON] Uri 클래스 : 부모 URI 구하기 (0) | 2021.08.22 |
[C#/COMMON] DateTime 구조체 : 일요일을 마지막 요일로 정렬하기 (0) | 2021.08.22 |
[C#/COMMON] Uri 클래스 : AbsolutePath/AbsoluteUri 속성 사용하기 (0) | 2021.08.22 |
[C#/COMMON] Environment 클래스 : GetEnvironmentVariable 정적 메소드를 사용해 환경 변수 값 구하기 (0) | 2021.08.22 |
[C#/COMMON] Environment 클래스 : SetEnvironmentVariable 정적 메소드를 사용해 환경 변수 값 설정하기 (0) | 2021.08.22 |
[C#/COMMON] StreamReader 클래스 : Read 메소드를 사용해 대용량 파일 읽기 (0) | 2021.08.22 |
[C#/COMMON] CSharpScript 클래스 : EvaluateAsync/RunAsync 정적 메소드를 사용해 런타임에서 C# 코드를 동적으로 컴파일하기 (0) | 2021.08.22 |
[C#/COMMON] 누겟 설치 : Microsoft.CodeAnalysis.CSharp.Scripting (0) | 2021.08.22 |
댓글을 달아 주세요