-
Notifications
You must be signed in to change notification settings - Fork 0
/
CsvReader.cs
249 lines (218 loc) · 6.31 KB
/
CsvReader.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
/// <summary>
/// Author: Mario Di Vece <mario@unosquare.com>
/// Date: 3/19/2014
/// Updated: 9/18/2014
/// License: MIT
/// </summary>
namespace RMX
{
using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;
using UnityEngine;
/// <summary>
/// A simple class to read small CSV files
/// Do not attempt to read very large files with this because
/// the entire contents of the file are read at once. Also,
/// The result is produced at once.
/// </summary>
public static class CsvReader
{
private const char DoubleQuote = '"';
private const char Comma = ',';
static public readonly Encoding Windows1252Encoding = Encoding.GetEncoding(1252);
public static string ToString(List<string> record)
{
return string.Join(",", record.Select(s => string.Format("\"{0}\"", s.Replace("\"", "\"\""))).ToArray());
}
/// <summary>
/// Defines the 3 different read states
/// </summary>
private enum ReadState
{
WaitingForNewField,
PushingNormal,
PushingQuoted,
}
/// <summary>
/// Parses the specified CSV string into a CsvRecordList.
/// </summary>
/// <param name="csvString">The CSV string.</param>
/// <returns></returns>
static public List<List<string> > Parse(string csvString)
{
var records = new List<List<string> >();
{
var lines = csvString.Split(new string[] { "\r", "\n" }, StringSplitOptions.RemoveEmptyEntries);
foreach (var line in lines)
{
if (string.IsNullOrEmpty(line))//TODO: account for whitespace
continue;
records.Add(CsvReader.ParseLine(line.Trim()));
}
}
return records;
}
/// <summary>
/// Reads the CSV records from specified path at once.
/// </summary>
/// <param name="path">The path.</param>
/// <returns></returns>
static public List<List<string> > Read(TextAsset file)
{
if (file == null)
throw new System.NullReferenceException ("Database file is null");
var csvLines = file.text.Split ('\n');//System.IO.File.ReadAllLines(path, encoding);
var csvRecords = new List<List<string> >();
for (var lineIndex = 0; lineIndex < csvLines.Length; lineIndex++)
{
var currentLine = csvLines[lineIndex];
var record = ParseLine(currentLine);
csvRecords.Add(record);
}
return csvRecords;
}
/// <summary>
/// Reads the CSV records from specified path at once.
/// </summary>
/// <param name="path">The path.</param>
/// <returns></returns>
static public List<List<string> > Read(string path)
{
throw new System.Exception ("Balls.");
// return Read(path, Encoding.UTF8);
}
/// <summary>
/// Reads a single line from the the currently open reader.
/// If a reader
/// </summary>
/// <param name="reader">The reader.</param>
/// <returns></returns>
static public List<string> ReadLine(System.IO.StreamReader reader)
{
string line = null;
if ((line = reader.ReadLine()) != null)
{
return ParseLine(line);
}
return null;
}
/// <summary>
/// Reads the specified csv file in the given file path.
/// </summary>
/// <param name="path">The path.</param>
/// <param name="encoding">The encoding.</param>
/// <returns></returns>
static public List<List<string> > Read(string path, Encoding encoding)
{
throw new System.Exception("Depricated");
//
// var csvLines = System.IO.File.ReadAllLines(path, encoding);
// var csvRecords = new List<List<string> >();
//
// for (var lineIndex = 0; lineIndex < csvLines.Length; lineIndex++)
// {
// var currentLine = csvLines[lineIndex];
// var record = ParseLine(currentLine);
// csvRecords.Add(record);
// }
//
// return csvRecords;
}
/// <summary>
/// Parses the line into a list of strings.
/// </summary>
/// <param name="line">The line.</param>
/// <returns></returns>
public static List<string> ParseLine(string line)
{
var values = new List<string>();
var currentValue = new StringBuilder(1024);
char currentChar;
Nullable<char> nextChar = null;
var currentState = ReadState.WaitingForNewField;
for (var charIndex = 0; charIndex < line.Length; charIndex++)
{
// Get the current and next character
currentChar = line[charIndex];
nextChar = charIndex < line.Length - 1 ? line[charIndex + 1] : new Nullable<char>();
// Perform logic based on state and decide on next state
switch (currentState)
{
case ReadState.WaitingForNewField:
{
currentValue.Length = 0;//.Clear();
if (currentChar == DoubleQuote)
{
currentState = ReadState.PushingQuoted;
continue;
}
else if (currentChar == Comma)
{
values.Add(currentValue.ToString());
currentState = ReadState.WaitingForNewField;
continue;
}
else
{
currentValue.Append(currentChar);
currentState = ReadState.PushingNormal;
continue;
}
}
case ReadState.PushingNormal:
{
// Handle field content delimiter by comma
if (currentChar == Comma)
{
currentState = ReadState.WaitingForNewField;
values.Add(currentValue.ToString().Trim());
currentValue.Length = 0;//();
continue;
}
// Handle double quote escaping
if (currentChar == DoubleQuote && nextChar == DoubleQuote)
{
// advance 1 character now. The loop will advance one more.
currentValue.Append(currentChar);
charIndex++;
continue;
}
currentValue.Append(currentChar);
break;
}
case ReadState.PushingQuoted:
{
// Handle field content delimiter by ending double quotes
if (currentChar == DoubleQuote && nextChar != DoubleQuote)
{
currentState = ReadState.PushingNormal;
continue;
}
// Handle double quote escaping
if (currentChar == DoubleQuote && nextChar == DoubleQuote)
{
// advance 1 character now. The loop will advance one more.
currentValue.Append(currentChar);
charIndex++;
continue;
}
currentValue.Append(currentChar);
break;
}
}
}
// push anything that has not been pushed (flush)
values.Add(currentValue.ToString().Trim());
return values;
}
}
public class CsvRecord : List<string>
{
public override string ToString()
{
return string.Join(",", this.Select(s => string.Format("\"{0}\"", s.Replace("\"", "\"\""))).ToArray());
}
}
}