CsvReader not applying configuration - c#

I am trying to parse a CSV file, with some lines commented out with the '#' character.
I am using the CsvHelper Configuration class to set the configuration for the CsvReader. However, it does not seems to register and still read my commented lines as input.
var config = new Configuration
{
Delimiter = ",",
Comment = '#',
Quote = '"',
HasHeaderRecord = false,
};
using (var stream = new StreamReader(filepath))
using (var reader = new CsvReader(stream, config))
{
while (reader.Read())
{
BsonDocument doc = new BsonDocument
{
{ "A", reader.GetField(0)},
{ "B", reader.GetField(1)},
{ "C", reader.GetField(2).ToLower()},
{ "D", reader.GetField(3)},
{ "E", Convert.ToBoolean(reader.GetField(4))},
{ "F", Convert.ToBoolean(reader.GetField(5))}
};
}
}
A sample of my data in my input.csv file:
#fieldA,fieldB,fieldC,fieldD,fieldE,fieldF
valueA,valueB,valueC,valueD,true,false
valueA,valueB,valueC,valueD,true,false
#valueA,valueB,valueC,valueD,true,false
valueA,valueB,valueC,valueD,true,false

Only the below works. Or you can don't explicitly state the comment char if it is the default '#'.
var config = new Configuration
{
Delimiter = ",",
//Comment = '#' //this does not work although # is the default
Comment = Convert.ToChar("#"),
Quote = '"',
HasHeaderRecord = false,
AllowComments = true,
};

I believe the AllowComments = true is the critical part. I was able to get it to work even when I set Comment = '#', but that isn't necessary since it is the default. I wonder if cultural settings could be playing a part.
var config = new Configuration
{
HasHeaderRecord = false,
AllowComments = true
};
using (var stream = new StreamReader(filepath))
using (var reader = new CsvReader(stream, config))
{
while (reader.Read())
{
BsonDocument doc = new BsonDocument
{
{ "A", reader.GetField(0)},
{ "B", reader.GetField(1)},
{ "C", reader.GetField(2).ToLower()},
{ "D", reader.GetField(3)},
{ "E", Convert.ToBoolean(reader.GetField(4))},
{ "F", Convert.ToBoolean(reader.GetField(5))}
};
}
}

There is a problem in CsvHelper when you try to prefix your csv file with comments while having HasHeaderRecord = true. The workaround is to put your csv header as the first line in the csv, then follow it by your comment block.
Since I believe this is a non-intuitive solution, I left an issue for the CsvHelper contributors to fix:
https://github.com/JoshClose/CsvHelper/issues/2039

Related

Convert CSV to JSON, How to address columns containing comma(,) using c#

I tried to convert CSV data to JSON. It quiet worked fine but few columns have comma, while converting to json, comma contained data is getting split.
This is the code I tried,
var path = #"C:xyz\\abc.csv";
var csv = new List<string[]>();
var lines = File.ReadAllLines(path);
foreach (string line in lines)
csv.Add(line.Split(','));
var properties = lines[0].Split(',');
var listObjResult = new List<Dictionary<string, string>>();
for (int i = 1; i < lines.Length; i++)
{
var objResult = new Dictionary<string, string>();
for (int j = 0; j < properties.Length; j++)
objResult.Add(properties[j], csv[i][j]);
listObjResult.Add(objResult);
}
var json = JsonConvert.SerializeObject(listObjResult, Formatting.Indented);
List<ABCModel> desrilize = JsonConvert.DeserializeObject<List<ABCModel>>(json);
return desrilize;
CSV data
employee,emp city,state,emp address
"abc","efg","lkj","building name"
"wer","sdf","qwe","afj Building, near cross"
In above third line contains comma, which should not get split while converting to json. Where as using above code, its getting split. Kindly help.
Also there is a space in "emp city", how to define jsonProperty for the same while creating model.
Expected json
[
{
"employee": "abc",
"emp city": "efg",
"state": "lkj",
"emp address": "building name"
},
{
"employee": "wer",
"emp city": "sdf",
"state": "qwe",
"emp address": "afj Building, near cross"
}
]
You can try with csvHelper or csv converter.
using csv:
var options = new CsvOptions // Defaults
{
RowsToSkip = 0, // Allows skipping of initial rows without csv data
SkipRow = (row, idx) => string.IsNullOrEmpty(row) || row[0] == '#',
Separator = '\0', // Autodetects based on first row
TrimData = false, // Can be used to trim each cell
Comparer = null, // Can be used for case-insensitive comparison for names
HeaderMode = HeaderMode.HeaderPresent, // Assumes first row is a header row
ValidateColumnCount = true, // Checks each row immediately for column count
ReturnEmptyForMissingColumn = false, // Allows for accessing invalid column names
Aliases = null, // A collection of alternative column names
AllowNewLineInEnclosedFieldValues = false, // Respects new line (either \r\n or \n) characters inside field values enclosed in double quotes.
AllowBackSlashToEscapeQuote = false, // Allows the sequence "\"" to be a valid quoted value (in addition to the standard """")
AllowSingleQuoteToEncloseFieldValues = false, // Allows the single-quote character to be used to enclose field values
NewLine = Environment.NewLine // The new line string to use when multiline field values are read (Requires "AllowNewLineInEnclosedFieldValues" to be set to "true" for this to have any effect.)
};
var csv = File.ReadAllText(fileName or filePath);
foreach (var line in CsvReader.ReadFromText(csv, options))
{
yourModel.Add(new yourModel()
{
StoneCode = line["Field1"],
StoneTypeName = line["Field2"],
});
}
To read your desired CSV input by using CsvHelper, this example should help you:
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using CsvHelper;
using CsvHelper.Configuration;
public class Program
{
public static void Main()
{
var csvContent = #"employee,emp city,state,emp address
""abc"",""efg"",""lkj"",""building name""
""wer"",""sdf"",""qwe"",""afj Building, near cross""";
List<Employee> employees;
using (var reader = new StringReader(csvContent))
using (var csv = new CsvReader(reader, CultureInfo.InvariantCulture))
{
csv.Context.RegisterClassMap<EmployeeMap>();
var records = csv.GetRecords<Employee>();
employees = records.ToList();
}
foreach (var employee in employees)
{
Console.WriteLine(System.Text.Json.JsonSerializer.Serialize(employee));
}
}
}
public class EmployeeMap : ClassMap<Employee>
{
public EmployeeMap()
{
Map(e => e.Name).Name("employee");
Map(e => e.City).Name("emp city");
Map(e => e.State).Name("state");
Map(e => e.Address).Name("emp address");
}
}
public class Employee
{
public string Name { get; set; }
public string City { get; set; }
public string State { get; set; }
public string Address { get; set; }
}
Here is another one to the list, Cinchoo ETL - an open source library does the job of converting CSV to JSON quickly as below
string csv = #"employee,emp city,state,emp address
""abc"",""efg"",""lkj"",""building name""
""wer"",""sdf"",""qwe"",""afj Building, near cross""";
using (var r = ChoCSVReader.LoadText(csv)
.WithFirstLineHeader()
.MayHaveQuotedFields()
)
{
using (var w = new ChoJSONWriter(Console.Out))
{
w.Write(r);
}
}
Output:
[
{
"employee": "abc",
"emp city": "efg",
"state": "lkj",
"emp address": "building name"
},
{
"employee": "wer",
"emp city": "sdf",
"state": "qwe",
"emp address": "afj Building, near cross"
}
]
Sample fiddle: https://dotnetfiddle.net/Dk4vtO

CSVHelper change/ manipulate headers before reading the csv

Am not in control of what csv file we may get and they ted to have an extra '_' or year added to the name from time to time which does not match with the mapping I have done.
Tried
var config = new CsvConfiguration(cultureInfo)
{
PrepareHeaderForMatch = args => args.Header.Replace("_", " "),
};
config.PrepareHeaderForMatch = args => Regex.Replace(args.Header, #"2021", string.Empty);
List<CSVInvoiceLineDetail> CSVParsedDataList = new();
using TextReader reader = new StreamReader(file.OpenReadStream());
using var csv = new CsvReader(reader, config);
csv.Read();
csv.ReadHeader();
while (csv.Read())
{
CSVParsedDataList.Add(csv.GetRecord<CSVInvoiceLineDetail>());
// Do something with the record.
}
but it doesn't work the headers are still how they were originally. Can anyone point out what am doing wrong here ?
Consider
var config = new CsvConfiguration(cultureInfo)
{
PrepareHeaderForMatch = args => args.Header.Replace("_", " ").Replace("2021","");,
};
Or if you want to strip all numbers and underscores out of headers:
var config = new CsvConfiguration(cultureInfo)
{
PrepareHeaderForMatch = args => Regex.Replace(args.Header, "[0-9_]", "")
};
Note that here it is replacing underscore with nothing, not space, so some adjustment to your declared header attributes may be required

Write Text file with tab-delimited in Asp.Net Core 2.2

Hi do you have any guides, work aid or step by step how to export to text with tab delimited. Im using Asp.Net Core 2.2 MVC EF. I want to export a list from my table.. I want to have a button where the user click in this DownloadFile Action will trigger.
public IActionResult DownloadFile()
{
var payments = new List<BdoPE>
{
new BdoPE
{
DocDateInDoc = "01/01/2019",
DocType = "DZ",
CompanyCode = "3000",
PosDateInDoc = "01/01/2019",
FiscalPeriod = "01",
CurrentKey = "PHP",
RefDocNum = "Over-The-Counter",
DocHeadT = "BDO",
PosKeyInNextLine = "40",
AccMatNextLine = "11231131",
AmountDocCur = "0000000010050",
ValDate = "01/01/2019",
AssignNum = "EEA",
ItemText = "1000136212 ",
PosKeyInNextLine2 = "15",
AccMatNextLine2 = "0115027FF",
AmountDocCur2 = "0000000010050",
BaseDateDueCal = "01/01/2019",
ItemText2 = "1000136212"
},
};
// I want this part to let the user select where they want to save the text file.
using (var writer = new StreamWriter("path\\to\\file.txt")) // not static location like this one.
using (var csv = new CsvWriter(writer))
{
csv.WriteHeader<BdoPE>();
csv.WriteRecord(payments);
}
// where should i put the delimiter part?
return;
}
You will need to setup the CsvWriter with a Configuration.
Thus, your code needs only a slight change:
[...]
var configuration = new CsvHelper.Configuration.Configuration();
configuration.Delimiter = '\t';
using (var csv = new CsvWriter(writer, configuration))
{
csv.WriteHeader<BdoPE>();
csv.WriteRecord(payments);
}
[...]
I use the code below to set the Delimiter using CsvHelper.
var config = new CsvConfiguration(CultureInfo.CurrentCulture)
{
Delimiter = "\t"
};

Header JSON Converting CSV to JSON

Hi im tring to convert CSV String to JSON, but the Header of the JSON has some issues with Encode i think.
Here the code and the Output:
[{...
"Endere_o_4": "",
"Endere_o_5": "",
"Endere_o_6": "",
"C_digo_Postal": "1000-045", ...]}
Expected Result: [{...
"Endereço_4": "",
"Endereço_5": "",
"Endereço_6": "",
"Código_Postal": "1000-045", ...]}
public void MssCSVtoJSON(string ssCSV, out string ssJSON)
{
ssJSON = "";
ChoCSVFileHeaderConfiguration headerConfiguration = new ChoCSVFileHeaderConfiguration(null, new System.Globalization.CultureInfo("pt-PT"));
ChoCSVRecordConfiguration config = new ChoCSVRecordConfiguration();
config.FileHeaderConfiguration = headerConfiguration;
StringBuilder sb = new StringBuilder();
using (var p = ChoCSVReader.LoadText(ssCSV,Encoding.Unicode, config, null).WithFirstLineHeader()) {
using (var w = new ChoJSONWriter(sb)) {
w.Configuration.Encoding = Encoding.Unicode;
w.Write(p);
}
}
ssJSON = sb.ToString();
// TODO: Write implementation for action
} // MssCSVtoJSON
It is known issue, put a fix and pushed ChoETL 1.1.0.5-alpha2 nuget package.
Here is working sample
string csv = #"Endereço_4, Endereço_5
1, 11
2, 22";
StringBuilder output = new StringBuilder();
using (var r = ChoCSVReader.LoadText(csv).WithFirstLineHeader())
{
using (var w = new ChoJSONWriter(output))
w.Write(r);
}
Console.WriteLine(output);
Output:
[
{
"Endereço_4": "1",
"Endereço_5": "11"
},
{
"Endereço_4": "2",
"Endereço_5": "22"
}
]

c# convert json string to .csv

I am trying to convert a json string, containing array elements, to a .csv file. Below is the json string format:
{"inputFile": [["Column1", "Column2", "Column3", "Column4", "Column5", "Column6", "Column7", "Column8", "Column9", "Column10"], ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J"], ["K", "L", "M", "N", "O", "P", "Q", "R", "S", "T"]]}
solved. Thanks heyNow.
dynamic dynObj = JsonConvert.DeserializeObject(json);
var rowElements = new List<string>();
foreach (var data in dynObj.inputFile)
{
var row = new List<string>();
foreach (var dataItem in data)
{
var item = Convert.ToString(dataItem);
row.Add(item);
}
rowElements.Add( String.Join(",", row)+"\n");
}
var CSV = String.Join("",rowElements);
Console.WriteLine(CSV);
For RaJN:
Updated code to replace json file path to json string:
StringBuilder msg = new StringBuilder();
using (var p = ChoJSONReader.LoadText(jsonString)
.WithJSONPath("$.inputFile[*]")
)
{
using (var w = new ChoCSVWriter(msg))
{
w.Write(p);
}
Console.WriteLine(msg.ToString());
}
try with newtonsoft jsonparser.
If you can get your JSON as a string..
dynamic dynObj = JsonConvert.DeserializeObject(jsonString);
string CSV = "";
foreach (var data in dynObj.inputFile)
{
List<string> row = new List<string>();
foreach(var dataItem in data)
{
row.Add(dataItem);
}
CSV+=string.Join(row, ",");
}
You will get 1 giant string containing all the values as a CSV.
Let us know if this is what you want.
Here is how you can generate CSV from your JSON file using Cinchoo ETL
StringBuilder msg = new StringBuilder();
using (var p = new ChoJSONReader("*** YOUR JSON FILE PATH ***")
.WithJSONPath("$.inputFile[*]")
)
{
using (var w = new ChoCSVWriter(msg))
{
w.Write(p);
}
Console.WriteLine(msg.ToString());
}
Output:
Column1,Column2,Column3,Column4,Column5,Column6,Column7,Column8,Column9,Column10
A,B,C,D,E,F,G,H,I,J
K,L,M,N,O,P,Q,R,S,T
UPDATE:
string json = #"
{
""inputFile"": [
[""Column1"", ""Column2"", ""Column3"", ""Column4"", ""Column5"", ""Column6"", ""Column7"", ""Column8"", ""Column9"", ""Column10""],
[ ""A"", ""B"", ""C"", ""D"", ""E"", ""F"", ""G"", ""H"", ""I"", ""J"" ],
[ ""K"", ""L"", ""M"", ""N"", ""O"", ""P"", ""Q"", ""R"", ""S"", ""T"" ]
]
}";
StringBuilder msg = new StringBuilder();
using (var p = ChoJSONReader.LoadText(json)
.WithJSONPath("$.inputFile[*]")
)
{
using (var w = new ChoCSVWriter(msg))
{
w.Write(p);
}
Console.WriteLine(msg.ToString());
}

Categories

Resources