chrisgregan
10 years ago
7 changed files with 270 additions and 215 deletions
@ -0,0 +1,218 @@ |
|||||||
|
using System; |
||||||
|
using System.Collections.Generic; |
||||||
|
using System.IO; |
||||||
|
using System.Text; |
||||||
|
|
||||||
|
namespace Ideafixxxer.CsvParser |
||||||
|
{ |
||||||
|
public class CsvParser |
||||||
|
{ |
||||||
|
private const char CommaCharacter = ','; |
||||||
|
private const char QuoteCharacter = '"'; |
||||||
|
|
||||||
|
#region Nested types |
||||||
|
|
||||||
|
private abstract class ParserState |
||||||
|
{ |
||||||
|
public static readonly LineStartState LineStartState = new LineStartState(); |
||||||
|
public static readonly ValueStartState ValueStartState = new ValueStartState(); |
||||||
|
public static readonly ValueState ValueState = new ValueState(); |
||||||
|
public static readonly QuotedValueState QuotedValueState = new QuotedValueState(); |
||||||
|
public static readonly QuoteState QuoteState = new QuoteState(); |
||||||
|
|
||||||
|
public abstract ParserState AnyChar(char ch, ParserContext context); |
||||||
|
public abstract ParserState Comma(ParserContext context); |
||||||
|
public abstract ParserState Quote(ParserContext context); |
||||||
|
public abstract ParserState EndOfLine(ParserContext context); |
||||||
|
} |
||||||
|
|
||||||
|
private class LineStartState : ParserState |
||||||
|
{ |
||||||
|
public override ParserState AnyChar(char ch, ParserContext context) |
||||||
|
{ |
||||||
|
context.AddChar(ch); |
||||||
|
return ValueState; |
||||||
|
} |
||||||
|
|
||||||
|
public override ParserState Comma(ParserContext context) |
||||||
|
{ |
||||||
|
context.AddValue(); |
||||||
|
return ValueStartState; |
||||||
|
} |
||||||
|
|
||||||
|
public override ParserState Quote(ParserContext context) |
||||||
|
{ |
||||||
|
return QuotedValueState; |
||||||
|
} |
||||||
|
|
||||||
|
public override ParserState EndOfLine(ParserContext context) |
||||||
|
{ |
||||||
|
context.AddLine(); |
||||||
|
return LineStartState; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private class ValueStartState : LineStartState |
||||||
|
{ |
||||||
|
public override ParserState EndOfLine(ParserContext context) |
||||||
|
{ |
||||||
|
context.AddValue(); |
||||||
|
context.AddLine(); |
||||||
|
return LineStartState; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private class ValueState : ParserState |
||||||
|
{ |
||||||
|
public override ParserState AnyChar(char ch, ParserContext context) |
||||||
|
{ |
||||||
|
context.AddChar(ch); |
||||||
|
return ValueState; |
||||||
|
} |
||||||
|
|
||||||
|
public override ParserState Comma(ParserContext context) |
||||||
|
{ |
||||||
|
context.AddValue(); |
||||||
|
return ValueStartState; |
||||||
|
} |
||||||
|
|
||||||
|
public override ParserState Quote(ParserContext context) |
||||||
|
{ |
||||||
|
context.AddChar(QuoteCharacter); |
||||||
|
return ValueState; |
||||||
|
} |
||||||
|
|
||||||
|
public override ParserState EndOfLine(ParserContext context) |
||||||
|
{ |
||||||
|
context.AddValue(); |
||||||
|
context.AddLine(); |
||||||
|
return LineStartState; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private class QuotedValueState : ParserState |
||||||
|
{ |
||||||
|
public override ParserState AnyChar(char ch, ParserContext context) |
||||||
|
{ |
||||||
|
context.AddChar(ch); |
||||||
|
return QuotedValueState; |
||||||
|
} |
||||||
|
|
||||||
|
public override ParserState Comma(ParserContext context) |
||||||
|
{ |
||||||
|
context.AddChar(CommaCharacter); |
||||||
|
return QuotedValueState; |
||||||
|
} |
||||||
|
|
||||||
|
public override ParserState Quote(ParserContext context) |
||||||
|
{ |
||||||
|
return QuoteState; |
||||||
|
} |
||||||
|
|
||||||
|
public override ParserState EndOfLine(ParserContext context) |
||||||
|
{ |
||||||
|
context.AddChar('\r'); |
||||||
|
context.AddChar('\n'); |
||||||
|
return QuotedValueState; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private class QuoteState : ParserState |
||||||
|
{ |
||||||
|
public override ParserState AnyChar(char ch, ParserContext context) |
||||||
|
{ |
||||||
|
//undefined, ignore " |
||||||
|
context.AddChar(ch); |
||||||
|
return QuotedValueState; |
||||||
|
} |
||||||
|
|
||||||
|
public override ParserState Comma(ParserContext context) |
||||||
|
{ |
||||||
|
context.AddValue(); |
||||||
|
return ValueStartState; |
||||||
|
} |
||||||
|
|
||||||
|
public override ParserState Quote(ParserContext context) |
||||||
|
{ |
||||||
|
context.AddChar(QuoteCharacter); |
||||||
|
return QuotedValueState; |
||||||
|
} |
||||||
|
|
||||||
|
public override ParserState EndOfLine(ParserContext context) |
||||||
|
{ |
||||||
|
context.AddValue(); |
||||||
|
context.AddLine(); |
||||||
|
return LineStartState; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private class ParserContext |
||||||
|
{ |
||||||
|
private readonly StringBuilder _currentValue = new StringBuilder(); |
||||||
|
private readonly List<string[]> _lines = new List<string[]>(); |
||||||
|
private readonly List<string> _currentLine = new List<string>(); |
||||||
|
|
||||||
|
public void AddChar(char ch) |
||||||
|
{ |
||||||
|
_currentValue.Append(ch); |
||||||
|
} |
||||||
|
|
||||||
|
public void AddValue() |
||||||
|
{ |
||||||
|
_currentLine.Add(_currentValue.ToString()); |
||||||
|
_currentValue.Remove(0, _currentValue.Length); |
||||||
|
} |
||||||
|
|
||||||
|
public void AddLine() |
||||||
|
{ |
||||||
|
_lines.Add(_currentLine.ToArray()); |
||||||
|
_currentLine.Clear(); |
||||||
|
} |
||||||
|
|
||||||
|
public List<string[]> GetAllLines() |
||||||
|
{ |
||||||
|
if (_currentValue.Length > 0) |
||||||
|
{ |
||||||
|
AddValue(); |
||||||
|
} |
||||||
|
if (_currentLine.Count > 0) |
||||||
|
{ |
||||||
|
AddLine(); |
||||||
|
} |
||||||
|
return _lines; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#endregion |
||||||
|
|
||||||
|
public string[][] Parse(string csvData) |
||||||
|
{ |
||||||
|
var context = new ParserContext(); |
||||||
|
|
||||||
|
string[] lines = csvData.Split('\n'); |
||||||
|
|
||||||
|
ParserState currentState = ParserState.LineStartState; |
||||||
|
foreach (string next in lines) |
||||||
|
{ |
||||||
|
foreach (char ch in next) |
||||||
|
{ |
||||||
|
switch (ch) |
||||||
|
{ |
||||||
|
case CommaCharacter: |
||||||
|
currentState = currentState.Comma(context); |
||||||
|
break; |
||||||
|
case QuoteCharacter: |
||||||
|
currentState = currentState.Quote(context); |
||||||
|
break; |
||||||
|
default: |
||||||
|
currentState = currentState.AnyChar(ch, context); |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
currentState = currentState.EndOfLine(context); |
||||||
|
} |
||||||
|
List<string[]> allLines = context.GetAllLines(); |
||||||
|
return allLines.ToArray(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,12 @@ |
|||||||
|
fileFormatVersion: 2 |
||||||
|
guid: 803c0d4d8bc9447d1b20e1f4fb86120f |
||||||
|
timeCreated: 1428171346 |
||||||
|
licenseType: Free |
||||||
|
MonoImporter: |
||||||
|
serializedVersion: 2 |
||||||
|
defaultReferences: [] |
||||||
|
executionOrder: 0 |
||||||
|
icon: {instanceID: 0} |
||||||
|
userData: |
||||||
|
assetBundleName: |
||||||
|
assetBundleVariant: |
Loading…
Reference in new issue