Skip to content

Commit dca4f2f

Browse files
committed
Changed delimiter detection to look line by line instead of the full buffer.
1 parent a588b7e commit dca4f2f

2 files changed

Lines changed: 67 additions & 13 deletions

File tree

src/CsvHelper/CsvParser.cs

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -264,22 +264,34 @@ public async Task<bool> ReadAsync()
264264
}
265265

266266
private void DetectDelimiter()
267-
{
267+
{
268268
var text = new string(buffer, 0, charsRead);
269-
var delimiterCounts = new Dictionary<string, int>();
270-
foreach (var delimiter in delimiterValues)
271-
{
272-
// Escape regex special chars to use as regex pattern.
273-
var pattern = Regex.Replace(delimiter, @"([.$^{\[(|)*+?\\])", "\\$1");
274-
delimiterCounts[delimiter] = Regex.Matches(text, pattern).Count;
275-
}
276269

277-
var maxCount = delimiterCounts.OrderByDescending(c => c.Value).First();
278-
if (maxCount.Value > 0)
270+
while (text.Length > 0)
279271
{
280-
delimiter = maxCount.Key;
281-
delimiterFirstChar = delimiter[0];
282-
configuration.Validate();
272+
var index = text.IndexOf(newLine);
273+
274+
var line = index > -1 ? text.Substring(0, index + newLine.Length) : text;
275+
276+
var delimiterCounts = new Dictionary<string, int>();
277+
foreach (var delimiter in delimiterValues)
278+
{
279+
// Escape regex special chars to use as regex pattern.
280+
var pattern = Regex.Replace(delimiter, @"([.$^{\[(|)*+?\\])", "\\$1");
281+
delimiterCounts[delimiter] = Regex.Matches(line, pattern).Count;
282+
}
283+
284+
var maxCount = delimiterCounts.OrderByDescending(c => c.Value).First();
285+
if (maxCount.Value > 0)
286+
{
287+
delimiter = maxCount.Key;
288+
delimiterFirstChar = delimiter[0];
289+
configuration.Validate();
290+
291+
break;
292+
}
293+
294+
text = index > -1 ? text.Substring(index + newLine.Length) : string.Empty;
283295
}
284296
}
285297

tests/CsvHelper.Tests/Parsing/DetectDelimiterTests.cs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,5 +195,47 @@ public void Parse_TextHasRegularCharDelimiter_DetectsDelimiter()
195195
Assert.Equal("þ", parser.Delimiter);
196196
}
197197
}
198+
199+
[Fact]
200+
public void Parse_MultipleLines_DetectsDelimiterFromFirstLineOnly()
201+
{
202+
var s = new StringBuilder();
203+
s.Append("Id;Name\r\n");
204+
s.Append("1,2,3,4;5,6,7,8\r\n");
205+
var config = new CsvConfiguration(CultureInfo.InvariantCulture)
206+
{
207+
Delimiter = "`",
208+
DetectDelimiter = true,
209+
DetectDelimiterValues = new[] { ",", ";" }
210+
};
211+
using (var reader = new StringReader(s.ToString()))
212+
using (var parser = new CsvParser(reader, config))
213+
{
214+
parser.Read();
215+
216+
Assert.Equal(";", parser.Delimiter);
217+
}
218+
}
219+
220+
[Fact]
221+
public void Parse_NoDelimiter_DoesNotDetect()
222+
{
223+
var s = new StringBuilder();
224+
s.Append("Id,Name\r\n");
225+
s.Append("1,one\r\n");
226+
var config = new CsvConfiguration(CultureInfo.InvariantCulture)
227+
{
228+
Delimiter = "`",
229+
DetectDelimiter = true,
230+
DetectDelimiterValues = new[] { ";" }
231+
};
232+
using (var reader = new StringReader(s.ToString()))
233+
using (var parser = new CsvParser(reader, config))
234+
{
235+
parser.Read();
236+
237+
Assert.Equal("`", parser.Delimiter);
238+
}
239+
}
198240
}
199241
}

0 commit comments

Comments
 (0)