@@ -138,12 +138,15 @@ pub const Parser = struct {
138
138
return null ;
139
139
}
140
140
defer index += 1 ;
141
+
141
142
self .err = self ._field_parser .err ;
142
143
if (self .err ) | _ | {
143
144
return null ;
144
145
}
146
+
145
147
end += f .field ._data .len + 1 ;
146
148
end = @min (end , self ._text .len );
149
+
147
150
if (f .row_end ) {
148
151
break ;
149
152
}
@@ -154,8 +157,27 @@ pub const Parser = struct {
154
157
assert (end <= self ._text .len );
155
158
assert (end >= start );
156
159
160
+ var data = self ._text [start .. end ];
161
+ if (data .len > 0 and data [data .len - 1 ] == self ._opts .column_line_end_prefix ) {
162
+ data = data [0.. (data .len - 1 )];
163
+ }
164
+
165
+ if (self ._field_parser .done ()) {
166
+ if (data .len == 0 ) {
167
+ return null ;
168
+ }
169
+ if (self ._opts .column_line_end_prefix ) | cr | {
170
+ if (data .len == 2 and data [0 ] == cr and data [1 ] == self ._opts .column_line_end ) {
171
+ return null ;
172
+ }
173
+ }
174
+ if (data .len == 1 and data [0 ] == self ._opts .column_line_end ) {
175
+ return null ;
176
+ }
177
+ }
178
+
157
179
return Row {
158
- ._data = self . _text [ start .. end ] ,
180
+ ._data = data ,
159
181
._opts = self ._opts ,
160
182
._len = index ,
161
183
};
@@ -830,33 +852,33 @@ test "row iterator" {
830
852
\\abc,"def",
831
853
\\abc"def""geh",
832
854
,
833
- .count = 1 ,
855
+ .count = 0 ,
834
856
.err = CsvReadError .UnexpectedQuote ,
835
857
},
836
858
.{
837
859
.input =
838
860
\\abc,"def",
839
861
\\"def"geh",
840
862
,
841
- .count = 1 ,
863
+ .count = 0 ,
842
864
.err = CsvReadError .UnexpectedEndOfFile ,
843
865
},
844
866
.{
845
867
.input =
846
868
\\abc,"def",
847
869
\\"def""geh,
848
870
,
849
- .count = 1 ,
871
+ .count = 0 ,
850
872
.err = CsvReadError .UnexpectedEndOfFile ,
851
873
},
852
874
.{
853
875
.input = "abc,serkj\r " ,
854
- .count = 1 ,
876
+ .count = 0 ,
855
877
.err = CsvReadError .InvalidLineEnding ,
856
878
},
857
879
.{
858
880
.input = "abc,serkj\r 1232,232" ,
859
- .count = 1 ,
881
+ .count = 0 ,
860
882
.err = CsvReadError .InvalidLineEnding ,
861
883
},
862
884
};
@@ -895,3 +917,49 @@ test "row and field iterator" {
895
917
896
918
try testing .expectEqual (fieldCount , cnt );
897
919
}
920
+
921
+ test "row end empty row" {
922
+ const repeat = 9441 ;
923
+ const testing = @import ("std" ).testing ;
924
+ const input = "2321234423412345678902322\r \n 3\r \n 4\r \n 5\r \n 6\r \n 7\r \n 8\r \n 9\r \n 1\r \n 2\r \n 3124,\r \n " ** repeat ;
925
+ const rows = 11 * repeat ;
926
+
927
+ var parser = Parser .init (input , .{});
928
+ var cnt : usize = 0 ;
929
+ while (parser .next ()) | _ | {
930
+ cnt += 1 ;
931
+ }
932
+
933
+ try testing .expectEqual (rows , cnt );
934
+ }
935
+
936
+ // For my own testing. I don't have the ability to distribute trips.csv at this time
937
+ // I uncomment this for testing locally against a 13MB test file
938
+
939
+ // test "csv" {
940
+ // var arena = std.heap.ArenaAllocator.init(std.testing.allocator);
941
+ // defer arena.deinit();
942
+ // const allocator = arena.allocator();
943
+ // var path_buffer: [std.fs.max_path_bytes]u8 = undefined;
944
+ // const path = try std.fs.realpathZ("trips.csv", &path_buffer);
945
+ //
946
+ // const file = try std.fs.openFileAbsolute(path, .{});
947
+ // defer file.close();
948
+ //
949
+ // const mb = (1 << 10) << 10;
950
+ // const csv = try file.readToEndAlloc(allocator, 500 * mb);
951
+ // var parser = Parser.init(csv, .{});
952
+ // var count: usize = 0;
953
+ // var lines: usize = 0;
954
+ // while (parser.next()) |row| {
955
+ // var iter = row.iter();
956
+ // lines += 1;
957
+ // while (iter.next()) |_| {
958
+ // count += 1;
959
+ // }
960
+ // }
961
+ //
962
+ // try std.testing.expectEqual(114393, lines);
963
+ // try std.testing.expectEqual(915144, count);
964
+ // }
965
+
0 commit comments