diff --git a/CsvLib.Tests/CsvFieldIndexerTests.cs b/CsvLib.Tests/CsvFieldIndexerTests.cs index 0a9b4ef..f55edcc 100644 --- a/CsvLib.Tests/CsvFieldIndexerTests.cs +++ b/CsvLib.Tests/CsvFieldIndexerTests.cs @@ -140,6 +140,66 @@ public class CsvFieldIndexerTests Assert.Equal(29, indexer.FieldIndex[1][3]); } + [Fact] + public void GenerateIndex__TwoLinesWithOneQuotedColumnsWithEscapedQuotes__TwoRows() + { + // --- Arrange + StringReader sr = new( + """ + "Hello \"World\"" + "Hello \"World\"" + """); + + // --- Act + CsvFieldIndexer indexer = new(); + indexer.GenerateIndex(sr); + + // --- Assert + + Assert.Equal(3, indexer.Index.Count); + Assert.Equal(0, indexer.Index[0]); + Assert.Equal(18, indexer.Index[1]); + Assert.Equal(36, indexer.Index[2]); + + Assert.Equal(2, indexer.FieldIndex.Count); + Assert.Equal(2, indexer.FieldIndex[0].Count); + Assert.Equal(1, indexer.FieldIndex[0][0]); + Assert.Equal(15, indexer.FieldIndex[0][1]); + Assert.Equal(2, indexer.FieldIndex[1].Count); + Assert.Equal(19, indexer.FieldIndex[1][0]); + Assert.Equal(33, indexer.FieldIndex[1][1]); + } + + [Fact] + public void GenerateIndex__TwoLinesWithOneQuotedColumnsWithManyEscapedQuotes__TwoRows() + { + // --- Arrange + StringReader sr = new( + """ + "Hello \"World\"" + "Hello \"World\"\"\"" + """); + + // --- Act + CsvFieldIndexer indexer = new(); + indexer.GenerateIndex(sr); + + // --- Assert + + Assert.Equal(3, indexer.Index.Count); + Assert.Equal(0, indexer.Index[0]); + Assert.Equal(18, indexer.Index[1]); + Assert.Equal(40, indexer.Index[2]); + + Assert.Equal(2, indexer.FieldIndex.Count); + Assert.Equal(2, indexer.FieldIndex[0].Count); + Assert.Equal(1, indexer.FieldIndex[0][0]); + Assert.Equal(15, indexer.FieldIndex[0][1]); + Assert.Equal(2, indexer.FieldIndex[1].Count); + Assert.Equal(19, indexer.FieldIndex[1][0]); + Assert.Equal(37, indexer.FieldIndex[1][1]); + } + [Fact] public void GenerateIndex__TwoLinesWithTwoQuotedColumnsWithUnicode__TwoRowsTwoFields() { diff --git a/CsvLib.Tests/CsvParserTest.cs b/CsvLib.Tests/CsvParserTest.cs index 0d21367..16fff83 100644 --- a/CsvLib.Tests/CsvParserTest.cs +++ b/CsvLib.Tests/CsvParserTest.cs @@ -36,7 +36,6 @@ public class CsvParserTest Assert.Equal("Hello World", parser.Data[0][0]); } - [Fact] public void Parse__TwoLinesOfPainText__TwoRows() { @@ -105,6 +104,50 @@ public class CsvParserTest Assert.Equal("World", parser.Data[1][1]); } + [Fact] + public void Parse__TwoLinesWithOneQuotedColumnsWithEscapedQuotes__TwoRows() + { + // --- Arrange + StringReader sr = new( + """ + "Hello \"World\"" + "Hello \"World\"" + """); + + // --- Act + CsvParser parser = new(); + parser.Parse(sr); + + // --- Assert + Assert.Equal(2, parser.Data.Count); + Assert.Single(parser.Data[0]); + Assert.Equal("Hello \"World\"", parser.Data[0][0]); + Assert.Single(parser.Data[1]); + Assert.Equal("Hello \"World\"", parser.Data[1][0]); + } + + [Fact] + public void Parse__TwoLinesWithOneQuotedColumnsWithManyEscapedQuotes__TwoRows() + { + // --- Arrange + StringReader sr = new( + """ + "Hello \"World\"" + "Hello \"World\"\"\"" + """); + + // --- Act + CsvParser parser = new(); + parser.Parse(sr); + + // --- Assert + Assert.Equal(2, parser.Data.Count); + Assert.Single(parser.Data[0]); + Assert.Equal("Hello \"World\"", parser.Data[0][0]); + Assert.Single(parser.Data[1]); + Assert.Equal("Hello \"World\"\"\"", parser.Data[1][0]); + } + [Fact] public void GenerateIndex__TwoLinesWithTwoQuotedColumnsWithUnicode__TwoRowsTwoFields() { diff --git a/CsvLib/CsvFieldIndexer.cs b/CsvLib/CsvFieldIndexer.cs index 30362c7..b7e1e03 100644 --- a/CsvLib/CsvFieldIndexer.cs +++ b/CsvLib/CsvFieldIndexer.cs @@ -102,6 +102,9 @@ public class CsvFieldIndexer else if (c == _escapeChar && _insideString) { i++; + long absolutePosition = lineOffset + i + unicodeDelta; + fieldStartPosition ??= absolutePosition; + fieldEndPosition = absolutePosition; } else if ((c == '\n' || c == '\r') && _insideString == false) {