C# Parse CSV to JSON Wrong Format - c#

Take a look and let me know what the hell i'm derping on ;)
[HttpPost]
public ActionResult Upload(HttpPostedFileBase File)
{
HttpPostedFileBase csvFile = Request.Files["adGroupCSV"];
byte[] buffer = new byte[csvFile.ContentLength];
csvFile.InputStream.Read(buffer, 0, csvFile.ContentLength);
string csvString = System.Text.Encoding.UTF8.GetString(buffer);
string[] lines = Regex.Split(csvString, "\r");
List<string[]> csv = new List<string[]>();
foreach (string line in lines)
{
csv.Add(line.Split(','));
}
string json = new System.Web.Script.Serialization.JavaScriptSerializer().Serialize(csv);
ViewData["CSV"] = json;
return View(ViewData);
}
This is how it is coming across:
json = "[[\"Col1\",\"Col2\",\"Col3\",\"Col4\",\"Col5\",\"Col6\"],[\"test\",\"test\",\"test\",\"test\",\"http://www.test.com/\",\"test/\"],[\"test\",\"test\",\"test\",\"test\",\"http://www.test.com...
This is how I want it:
{"Col1":"test","Col2":"test","Col3":"test","Col4":"test","Col5":"http://www.test.com/","Col6":"test/"}
Here is an example of the CSV
Col1,Col2,Col3,Col4,Col5,Col6
Test1,Test1,Test1,test1,test.test,test/
Test2,Test2,Test2,test2,test.test,test/
Test3,Test3,Test3,test3,test.test,test/
Test4,Test4,Test4,test4,test.test,test/

You need a dictionary. Just replace
List<string[]> csv = new List<string[]>();
foreach (string line in lines)
{
csv.Add(line.Split(','));
}
with
var csv = lines.Select(l => l.Split(',')
.Select((s,i)=>new {s,i})
.ToDictionary(x=>"Col" + (x.i+1), x=>x.s));
It should work...
EDIT
var lines = csvString.Split(new char[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);
var cols = lines[0].Split(',');
var csv = lines.Skip(1)
.Select(l => l.Split(',')
.Select((s, i) => new {s,i})
.ToDictionary(x=>cols[x.i],x=>x.s));
var json = new JavaScriptSerializer().Serialize(csv);

It looks like you have a an array of string arrays when you just want one object with all your columns as properties on it.
Instead of building up your
List<string[]> csv = new List<string[]>();
Can you make a new object from your JSON, like this:
public class UploadedFileObject
{
public string Col1 { get; set; }
public string Col2 { get; set; }
public string Col3 { get; set; }
public string Col4 { get; set; }
public string Col5 { get; set; }
public string Col6 { get; set; }
}
[HttpPost] public ActionResult Upload(HttpPostedFileBase File)
{
HttpPostedFileBase csvFile = Request.Files["adGroupCSV"];
byte[] buffer = new byte[csvFile.ContentLength];
csvFile.InputStream.Read(buffer, 0, csvFile.ContentLength);
string csvString = System.Text.Encoding.UTF8.GetString(buffer);
string[] lines = Regex.Split(csvString, "\r");
List<UploadedFileObject> returnObject = new List<UploadedFileObject>();
foreach (string line in lines)
{
String[] lineParts = line.Split(',');
UploadedFileObject lineObject = new UploadedFileObject();
lineObject.Col1 = lineParts[0];
lineObject.Col2 = lineParts[1];
lineObject.Col3 = lineParts[2];
lineObject.Col4 = lineParts[3];
lineObject.Col5 = lineParts[4];
lineObject.Col6 = lineParts[5];
returnObject.add(lineObject);
}
string json = new System.Web.Script.Serialization.JavaScriptSerializer().Serialize(returnObject);
ViewData["CSV"] = json;
return View(ViewData);
}

In line with the previous answer, perhaps you could use ServiceStack to deserialize the CSV into an array of objects, then re-serialize it using ServiceStack's JSON serializer?
http://www.servicestack.net/docs/text-serializers/json-csv-jsv-serializers

You need to ensure you are using the format that the JavaScriptSerializer expects you to.
Since you are giving it a List<string[]> it is formatting it as:
"[[list1Item1,list1Item2...],[list2Item1,list2Item2...]]"
Which would correlate in your file as row1 -> list1 etc.
However what you want is the first item from the first list, lining up with the first item in the second list and so on.
I don't know about the exact workings of JavaScriptSerializer, but you could try giving it a Dictionary instead of a List<string[]>, assuming you only had one line of data (two lines total).
This would involve caching the first two lines and doing the following:
for (int i = 0; i < first.Length; i++)
{
dict.Add(first[i],second[i]);
}

Related

CSV File with cells containing commas, Reading data into C# Program

I'm writing a program to read in CSV files and validate the data. The csv file is comma delimited.
The csv file contains a sales order that is retrieved online so we can't actually edit the CSV file itself. I need to read in the file and split it into the cells. However, the product description will contain further commas which is affecting how I access the data.
My code for pulling the values out is below.
private void csvParse()
{
List<string> products = new List<string>();
List<string> quantities = new List<string>();
List<string> price = new List<string>();
using (var reader = new StreamReader(txt_filePath.Text.ToString()))
{
while (!reader.EndOfStream)
{
var line = reader.ReadLine();
var values = line.Split(',');
products.Add(values[0]);
quantities.Add(values[2]);
values[3] = values[3].Substring(4);
price.Add(values[3]);
}
}
if (validateData(products, quantities, price) != "")
{
MessageBox.Show(validateData(products, quantities, price));
}
}
Is there anyway to ignore the columns in a set cell or can the columns distinguished by another delimiter?
A snippet of a row in my csv file is below.
The raw CSV data is below:
TO12345,"E45 Dermatological Moisturising Lotion, 500 ml",765,GBP 1.75
You can use LinqToCSV from nuGet. ie:
void Main()
{
List<MyData> sample = new List<MyData> {
new MyData {Id=1, Name="Hammer", Description="Everything looks like a nail to a hammer, doesn't it?"},
new MyData {Id=2, Name="C#", Description="A computer language."},
new MyData {Id=3, Name="Go", Description="Yet another language, from Google, cross compiles natively."},
new MyData {Id=3, Name="BlahBlah"},
};
string fileName = #"c:\temp\MyCSV.csv";
File.WriteAllText(fileName,"Id,My Product Name,Ignore1,Ignore2,Description\n");
File.AppendAllLines(fileName, sample.Select(s => $#"{s.Id},""{s.Name}"",""ignore this"",""skip this too"",""{s.Description}"""));
CsvContext cc = new CsvContext();
CsvFileDescription inputFileDescription = new CsvFileDescription
{
SeparatorChar = ',',
FirstLineHasColumnNames = true,
IgnoreUnknownColumns=true
};
IEnumerable<MyData> fromCSV = cc.Read<MyData>(fileName, inputFileDescription);
foreach (var d in fromCSV)
{
Console.WriteLine($#"ID:{d.Id},Name:""{d.Name}"",Description:""{d.Description}""");
}
}
public class MyData
{
[CsvColumn(FieldIndex = 1, Name="Id", CanBeNull = false)]
public int Id { get; set; }
[CsvColumn(FieldIndex = 2, Name="My Product Name",CanBeNull = false, OutputFormat = "C")]
public string Name { get; set; }
[CsvColumn(FieldIndex = 5, Name="Description",CanBeNull = true, OutputFormat = "C")]
public string Description { get; set; }
}
It should work..:)
var csvSplit = new Regex("(?:^|,)(\"(?:[^\"]+|\"\")*\"|[^,]*)", RegexOptions.Compiled);
string[] csvlines = File.ReadAllLines(txt_filePath.Text.ToString());
var query = csvlines.Select(csvline => new
{
data = csvSplit.Matches(csvline)
}).Select(t => t.data);
var row = query.Select(matchCollection =>
(from Match m in matchCollection select (m.Value.Contains(',')) ? m.Value.Replace(",", "") : m.Value)
.ToList()).ToList();
You can also use the Microsoft.VisualBasic.FileIO.TextFieldParser class. More detailed answer here: TextFieldParser

c# add textfile to 2 dimensional array

I'm trying to read a text file, which contains proxys into a 2 dimensional array.
The text file looks like the following:
00.00.00.00:80
00.00.00.00:80
00.00.00.00:80
00.00.00.00:80
00.00.00.00:80
How could I seperate the ip from the port?`
So my array would look like the following:
[00.00.00.00][80]
Current code:
public void readProxyList(string FileName)
{
using (StreamReader sr = new StreamReader(FileName, Encoding.Default))
{
string text = sr.ReadToEnd();
string[] lines = text.Split('\r');
foreach (string s in lines)
{
}
}
}
If you are not expecting the file to be too large you could use File.ReadAllLines to read in each line. Then to split, just use String.Split with ':' as your token.
Example:
var lines = File.ReadAllLines(FileName));
var array = new string[lines.Length,2];
for(int i=0; i < lines.Length; i++)
{
var temp = lines[i].Split(':');
array[i,0] = temp[0];
array[i,1] = temp[1];
}
Edit
If you expect that the file may be large, instead of using ReadAllLines you can use File.ReadLines. This method returns an IEnumerable<string> and will not read the whole file at once. In this case, I would probably opt away from the 2d array and make a simple class (call it IpAndPort or something like that) and create a list of those.
Example:
public sealed class IpAndPort
{
public string Ip { get; private set; }
public string Port { get; private set; }
public IpAndPort (string ip, string port)
{
Ip = ip;
Port = port;
}
}
var list = new List<IpAndPort>();
foreach(var line in File.ReadLines(FileName))
{
var temp = line.Split(':');
list.Add(new IpAndPort(temp[0], temp[1]);
}
Try this:
public IEnumerable<string> GetProxyList(string FileName)
{
string[] allLines = File.ReadAllLines(FileName);
var result = new List<string>(allLines.Length);
foreach (string line in allLines)
{
var splittedLine = line.Split(':');
result.Add($"[{splittedLine[0]}][{splittedLine[1]}]");
}
return result;
}

How to insert database what read four values in txt file?

I'm using c# MVC project.
I have a customer class and customer table.I have a Insert function with four parameter name , surname ,phone,address.I want to read .txt file line by line and split with "," and use this Insert function but I don't know how can create algorithm.
static void AddCustomer(string Name, string Surname, string Phone, string Address)
{
using (var session = NHibernateHelper.OpenSession())
{
using (var transaction = session.BeginTransaction())
{
var customer = new Customer
{
Name = Name,
Surname = Surname,
Phone = Phone,
Address = Address,
};
session.Save(customer);
transaction.Commit();
}
}
}
while ((line = file.ReadLine()) != null)
{
string text = file.ReadToEnd();
string[] lines = text.Split(',');
for (int i = 0; i < lines.Length; i++)
{
//HOW CAN I USER ADDCUSTOMER()
}
counter++;
}
You've almost got it. Assuming file is a StreamReader, you can just split the current line on comma, and pass the separate parts to the AddCustomer method:
while ((line = file.ReadLine()) != null)
{
// Split the line on comma
var lineParts = line.Split(',');
string name = lineParts[0];
string surname = lineParts[1];
string phone = lineParts[2];
string address = lineParts[3];
AddCustomer(name, surname, phone, address);
}
Please note that this does no error checking at all (lineParts[1] will blow up if there's no comma in the given line) and that this is a bad way to parse CSV (if the data contains comma's, which addresses tend to do, it'll not work properly). Use a CSV parsing library.
See Parsing CSV files in C#, with header and plenty of other questions about CSV, where it is suggested that you use the FileHelpers library. Your class that maps to and from the CSV file will look like this:
[DelimitedRecord(",")]
[IgnoreEmptyLines()]
public class MyProduct
{
[FieldOrder(0)]
public string Name { get; set; }
[FieldOrder(1)]
public string Surname { get; set; }
[FieldOrder(2)]
public string Phone { get; set; }
[FieldOrder(3)]
public string Address { get; set; }
}
And the code to read the file:
var engine = new FileHelperEngine<CustomerCsvRecord>();
CustomerCsvRecord[] customers = engine.ReadFile(fileName);
foreach (var customer in customers)
{
AddCustomer(customer.Name, customer.Surname, customer.Phone, customer.Address);
}
This will do your job.
string fileContent = System.IO.File.ReadAllText("YOUR_FILE_PATH");
//assumeing each customer record will be on separate line
string[] lines = fileContent.Split(new string [] {Environment.NewLine}, StringSplitOptions.RemoveEmptyEntries);
foreach (string line in lines)
{
//assuming a single line content will be like this "name,surname,phone,address"
string[] items = line.Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries);
Customer cust = new Customer();
cust.Name = items[0];
cust.Surname = items[1];
cust.Phone = items[2];
cust.Address = items[3];
//now use this 'cust' object
}

How to split string containing multiple delimeters of each and every line of text file?

This is the Input my file contains:
50|Hallogen|Mercury|M:4;C:40;A:1
90|Oxygen|Mars|M:10;C:20;A:00
5|Hydrogen|Saturn|M:33;C:00;A:3
Now i want to split each and every line of my text file and store in my class file like :
Expected output:
Planets[0]:
{
Number:50
name: Hallogen
object:Mercury
proportion[0]:
{
Number:4
},
proportion[1]:
{
Number:40
},
proportion[2]:
{
Number:1
}
}
etc........
My class file to store all this values:
public class Planets
{
public int Number { get; set; } //This field points to first cell of every row.output 50,90,5
public string name { get; set; } //This field points to Second cell of every row.output Hallogen,Oxygen,Hydrogen
public string object { get; set; } ////This field points to third cell of every row.output Mercury,Mars,Saturn
public List<proportion> proportion { get; set; } //This will store all proportions with respect to planet object.
//for Hallogen it will store 4,40,1.Just store number.ignore M,C,A initials.
//for oxygen it will store 10,20,00.Just store number.ignore M,C,A initials.
}
public class proportion
{
public int Number { get; set; }
}
This is what i have done:
List<Planets> Planets = new List<Planets>();
using (StreamReader sr = new StreamReader(args[0]))
{
String line;
while ((line = sr.ReadLine()) != null)
{
string[] parts = Regex.Split(line, #"(?<=[|;-])");
foreach (var item in parts)
{
var Obj = new Planets();//Not getting how to store it but not getting proper output in parts
}
Console.WriteLine(line);
}
}
Without you having to change any of your logic in "Planets"-class my fast solution to your problem would look like this:
List<Planets> Planets = new List<Planets>();
using (StreamReader sr = new StreamReader(args[0]))
{
String line;
while ((line = sr.ReadLine()) != null)
{
Planets planet = new Planets();
String[] parts = line.Split('|');
planet.Number = Convert.ToInt32(parts[0]);
planet.name = parts[1];
planet.obj = parts[2];
String[] smallerParts = parts[3].Split(';');
planet.proportion = new List<proportion>();
foreach (var item in smallerParts)
{
proportion prop = new proportion();
prop.Number =
Convert.ToInt32(item.Split(':')[1]);
planet.proportion.Add(prop);
}
Planets.Add(planet);
}
}
Oh before i forget it, you should not name your property of class Planets "object" because "object" is a keyword for the base class of everything, use something like "obj", "myObject" ,"planetObject" just not "object" your compiler will tell you the same ;)
To my understanding, multiple delimiters are maintained to have a nested structure.
You need to split the whole string first based on pipe, followed by semi colon and lastly by colon.
The order of splitting here is important. I don't think you can have all the tokens at once by splitting with all 3 delimiters.
Try following code for same kind of data
var values = new List<string>
{
"50|Hallogen|Mercury|M:4;C:40;A:1",
"90|Oxygen|Mars|M:10;C:20;A:00",
"5|Hydrogen|Saturn|M:33;C:00;A:3"
};
foreach (var value in values)
{
var pipeSplitted = value.Split('|');
var firstNumber = pipeSplitted[0];
var name = pipeSplitted[1];
var objectName = pipeSplitted[2];
var semiSpltted = value.Split(';');
var secondNumber = semiSpltted[0].Split(':')[1];
var thirdNumber = semiSpltted[1].Split(':')[1];
var colenSplitted = value.Split(':');
var lastNumber = colenSplitted[colenSplitted.Length - 1];
}
The most straigtforward solution is to use a regex where every (sub)field is matched inside a group
var subjectString = #"50|Hallogen|Mercury|M:4;C:40;A:1
90|Oxygen|Mars|M:10;C:20;A:00
5|Hydrogen|Saturn|M:33;C:00;A:3";
Regex regexObj = new Regex(#"^(.*?)\|(.*?)\|(.*?)\|M:(.*?);C:(.*?);A:(.*?)$", RegexOptions.Multiline);
Match match = regexObj.Match(subjectString);
while (match.Success) {
match.Groups[1].Value.Dump();
match.Groups[2].Value.Dump();
match.Groups[3].Value.Dump();
match.Groups[4].Value.Dump();
match.Groups[5].Value.Dump();
match.Groups[6].Value.Dump();
match = match.NextMatch();
}
If I understand correctly, your input is well formed. In this case you could use something like this:
string[] parts = Regex.Split(line, #"[|;-]");
var planet = new Planets(parts);
...
public Planets(string[] parts) {
int.TryParse(parts[0], this.Number);
this.name = parts[1];
this.object = parts[2];
this.proportion = new List<proportion>();
Regex PropRegex = new Regex("\d+");
for(int i = 3; i < parts.Length; i++){
Match PropMatch = PropRegex.Match(part[i]);
if(PropMatch.IsMatch){
this.proportion.Add(int.Parse(PropMatch.Value));
}
}
}

Need to convert comma separated data from a file into a list of object

I need to read data from a .csv file and store the header and the content in my object in the following format. A list of the below mentioned class.
public class MappingData
{
private string ColumnName { get; set; }
private List<string> Data { get; set; }
}
So for example say I have a table like as shown below,
| Name | Phone | City |
|:-----------|------------:|:------------:|
| Yassser | 32342342234 | Mumbai
| Sachin | 32342342234 | Surat
| Will | 32342342234 | London
So for the above data my class should have 3 objects, first object will have the following details
ColumnName : 'Name'
Data: ['Yasser', 'Sachin', 'Will']
so, this is what I am trying to do, Below is what I have started with. I am reading the file using stream reader and spliting each line with comma seperator.
private List<MappingData> GetData(string filename)
{
var data = new List<MappingData>();
string fullPath = GetFilePath(filename);
StreamReader reader = new StreamReader(fullPath);
while (!reader.EndOfStream)
{
string line = reader.ReadLine();
if (!String.IsNullOrWhiteSpace(line))
{
string[] values = line.Split(',');
}
}
return data;
}
can some one please help me mold this data into the required format. Thanks.
You should create a small int variable (or bool if you prefer) to determine whether the first row has been completed :
And create each of the list objects you will need (mpName, mpPhone, mpCity), on the first row you set the ColumnName property and on the subsequent rows you add to the MappingData's data list.
Then you add each of the lists (mpName, mpPhone, mpCity) to the data list for the method and return this.
private List<MappingData> GetData(string filename) {
List<MappingData> data = new List<MappingData>();
int NumRow = 0;
MappingData mpName = new MappingData();
MappingData mpPhone = new MappingData();
MappingData mpCity = new MappingData();
string fullPath = GetFilePath(filename);
StreamReader reader = new StreamReader(fullPath);
while (!reader.EndOfStream) {
string line = reader.ReadLine();
if (!String.IsNullOrWhiteSpace(line)) {
string[] values = line.Split(',');
if (NumRow == 0) {
mpName.ColumnName = values[0];
mpPhone.ColumnName = values[1];
mpCity.ColumnName = values[2];
NumRow = 1;
} else {
mpName.Data.Add(values[0]);
mpPhone.Data.Add(values[1]);
mpCity.Data.Add(values[2]);
}
}
}
data.Add(mpName);
data.Add(mpPhone);
data.Add(mpCity);
return data;
}
Hope this helps.
There's an excellent library for processing the CSV files.
KentBoogard
It is very easy with the above third party library to read content from the CSV files.
I would suggest this because you just seem to be starting and don't re invent the wheel.
Still, if you want to process the file in your own way, here's one working implementation. Enjoy
var csvData = File.ReadAllLines("d:\\test.csv");
var dataRows = csvData.Skip(1).ToList();
var csvHeaderColumns = csvData.First().Split(',').ToList();
var outputList = new List<MappingData>();
foreach (var columnName in csvHeaderColumns)
{
var obj = new MappingData { columnName = columnName, data = new List<string>() };
foreach (var rowStrings in dataRows.Select(dataRow => dataRow.Split(',').ToList()))
{
obj.data.Add(rowStrings[csvHeaderColumns.IndexOf(columnName)]);
}
outputList.Add(obj);
}
This will populate your MappingData class.
Assuming the rest of your method is correct then try this:
private List<MappingData> GetData(string filename)
{
var raw = new List<string[]>();
var data = new List<MappingData>();
string fullPath = GetFilePath(filename);
using(var reader = new StreamReader(fullPath))
{
while (!reader.EndOfStream)
{
string line = reader.ReadLine();
if (!String.IsNullOrWhiteSpace(line))
{
raw.Add(line.Split(','));
}
}
}
Func<int, MappingData> extract =
n => new MappingData()
{
ColumnName = raw[0][n],
Data = raw.Skip(1).Select(x => x[n]).ToList(),
};
data.Add(extract(0));
data.Add(extract(1));
data.Add(extract(2));
return data;
}
You'd have to make you MappingData properties accessible though.

Categories

Resources