Example
import std.algorithm;import std.array;import std.csv;import std.stdio;import std.typecons;void main(){auto text ="Joe,Carpenter,300000\nFred,Blacksmith,400000\r\n";foreach (record; csvReader!(Tuple!(string, string,int))(text)) { writefln("%s works as a %s and earns $%d per year", record[0], record[1], record[2]); }// To read the same string from the file "filename.csv":auto file = File("filename.csv","r");foreach (record; file.byLine.joiner("\n").csvReader!(Tuple!(string, string,int))) { writefln("%s works as a %s and earns $%d per year", record[0], record[1], record[2]); }}}When an input contains a header theContents can be specified as an associative array. Passing null to signify that a header is present.
auto text ="Name,Occupation,Salary\r" ~"Joe,Carpenter,300000\nFred,Blacksmith,400000\r\n";foreach (record; csvReader!(string[string]) (text,null)){ writefln("%s works as a %s and earns $%s per year.", record["Name"], record["Occupation"], record["Salary"]);}// To read the same string from the file "filename.csv":auto file = File("filename.csv","r");foreach (record; csvReader!(string[string]) (file.byLine.joiner("\n"),null)){ writefln("%s works as a %s and earns $%s per year.", record["Name"], record["Occupation"], record["Salary"]);}This module allows content to be iterated by record stored in a struct, class, associative array, or as a range of fields. Upon detection of an error an CSVException is thrown (can be disabled). csvNextToken has been made public to allow for attempted recovery. Disabling exceptions will lift many restrictions specified above. A quote can appear in a field if the field was not quoted. If in a quoted field any quote by itself, not at the end of a field, will end processing for that field. The field is ended when there is no input, even if the quote was not closed.
Sourcestd/csv.d
CSVException:object.Exception;import std.exception : collectException;import std.algorithm.searching : count;string text ="a,b,c\nHello,65";auto ex = collectException!CSVException(csvReader(text).count);// "(Row: 0, Col: 0) Row 2's length 2 does not match previous length of 3."writeln(ex.toString);
import std.exception : collectException;import std.algorithm.searching : count;import std.typecons : Tuple;string text ="a,b\nHello,65";auto ex = collectException!CSVException(csvReader!(Tuple!(string,int))(text).count);// "(Row: 1, Col: 2) Unexpected 'b' when converting from type string to type int"writeln(ex.toString);
row;col;IncompleteCellException:std.csv.CSVException;import std.exception : assertThrown;string text ="a,\"b,c\nHello,65,2.5";assertThrown!IncompleteCellException(text.csvReader(["a","b","c"]));
partialData;HeaderMismatchException:std.csv.CSVException;import std.exception : assertThrown;string text ="a,b,c\nHello,65,2.5";assertThrown!HeaderMismatchException(text.csvReader(["b","c","invalid"]));
Malformed: int;import std.algorithm.comparison : equal;import std.algorithm.searching : count;import std.exception : assertThrown;string text ="a,b,c\nHello,65,\"2.5";assertThrown!IncompleteCellException(text.csvReader.count);// ignore the exceptions and try to handle invalid CSVauto firstLine = text.csvReader!(string,Malformed.ignore)(null).front;assert(firstLine.equal(["Hello","65","2.5"]));
ignorethrowExceptioncsvReader(Contents = string, Malformed ErrorLevel = Malformed.throwException, Range, Separator = char)(Rangeinput, Separatordelimiter = ',', Separatorquote = '"', boolallowInconsistentDelimiterCount = false)csvReader(Contents = string, Malformed ErrorLevel = Malformed.throwException, Range, Header, Separator = char)(Rangeinput, Headerheader, Separatordelimiter = ',', Separatorquote = '"', boolallowInconsistentDelimiterCount = false)csvReader(Contents = string, Malformed ErrorLevel = Malformed.throwException, Range, Header, Separator = char)(Rangeinput, Headerheader, Separatordelimiter = ',', Separatorquote = '"', boolallowInconsistentDelimiterCount = false)input.header can be provided. The first record will be read inas the header. IfContents is a struct then the header provided isexpected to correspond to the fields in the struct. WhenContents isnot a type which can contain the entire record, theheader must beprovided in the same order as the input or an exception is thrown.header argument is provided, the returned range provides aheader field for accessing the header from the input in array form.import std.algorithm.comparison : equal;string text ="76,26,22";auto records = text.csvReader!int;assert(records.equal!equal([ [76, 26, 22],]));
import std.algorithm.comparison : equal;string text ="Hello;65;2.5\nWorld;123;7.5";struct Layout{ string name;int value;double other;}auto records = text.csvReader!Layout(';');assert(records.equal([ Layout("Hello", 65, 2.5), Layout("World", 123, 7.5),]));
string text ="A \" is now part of the data";auto records = text.csvReader!(string, Malformed.ignore);auto record = records.front;writeln(record.front);// text
import std.algorithm.comparison : equal;string text ="a,b,c\nHello,65,63.63\nWorld,123,3673.562";auto records = text.csvReader!int(["b"]);assert(records.equal!equal([ [65], [123],]));
import std.algorithm.comparison : equal;string text ="a,b,c\nHello,65,2.5\nWorld,123,7.5";struct Layout{int value;double other; string name;}auto records = text.csvReader!Layout(["b","c","a"]);assert(records.equal([ Layout(65, 2.5,"Hello"), Layout(123, 7.5,"World")]));
header field.string text ="a,b,c\nHello,65,63.63";auto records = text.csvReader(null);writeln(records.header);// ["a", "b", "c"]
csvReader function as shown below.import std.algorithm.comparison : equal;string text ="76,26,22\n1,2\n3,4,5,6";auto records = text.csvReader!int(',', '"',true);assert(records.equal!equal([ [76, 26, 22], [1, 2], [3, 4, 5, 6]]));
import std.algorithm.comparison : equal;staticstruct Three{int a;int b;int c;}string text ="76,26,22\n1,2\n3,4,5,6";auto records = text.csvReader!Three(',', '"',true);assert(records.equal([ Three(76, 26, 22), Three(1, 2, 0), Three(3, 4, 5)]));
import std.algorithm.comparison : equal;auto text ="Name,Occupation,Salary\r" ~"Joe,Carpenter,300000\nFred,Blacksmith\r\n";auto r =csvReader!(string[string])(text,null, ',', '"',true);assert(r.equal([ ["Name" :"Joe","Occupation" :"Carpenter","Salary" :"300000" ], ["Name" :"Fred","Occupation" :"Blacksmith" ]]));
csvNextToken(Range, Malformed ErrorLevel = Malformed.throwException, Separator, Output)(ref Rangeinput, ref Outputans, Separatorsep, Separatorquote, boolstartQuoted = false)Rangeinput | Any CSV input |
Outputans | The first field in the input |
Separatorsep | The character to represent a comma in the specification |
Separatorquote | The character to represent a quote in the specification |
boolstartQuoted | Whether the input should be considered to already be in quotes |
import std.array : appender;import std.range.primitives : popFront;string str ="65,63\n123,3673";auto a = appender!(char[])();csvNextToken(str,a,',','"');writeln(a.data);// "65"writeln(str);// ",63\n123,3673"str.popFront();a.shrinkTo(0);csvNextToken(str,a,',','"');writeln(a.data);// "63"writeln(str);// "\n123,3673"str.popFront();a.shrinkTo(0);csvNextToken(str,a,',','"');writeln(a.data);// "123"writeln(str);// ",3673"