Parsing a vCard file - c#

I want to retrieve the data from a .vcf file. It is in vcf format.
I need the regular expression formula for each item of data mentioned below. I tried but could not make it work.
BEGIN:VCARD
VERSION:2.1
FN;CHARSET=utf-8:s James F ' Ernande.
ADR;WORK;X-EDIT=0;X-POS=280,43,54,269,0,0,0,0;CHARSET=utf-8:;;P.O. Box No: 570, P. C-112, Ruwi Muscat, Sultanate Ofoman;;;;
X-IS-TAKE-ADR;CHARSET=utf-8:23.62866567746918;58.26649072858852;
N;X-EDIT=0;X-POS=33,89,29,178;CHARSET=utf-8:s;James F ' Ernande. ;;;
EMAIL;WORK;X-EDIT=0;X-POS=116,59,26,237;CHARSET=utf-8:james#om.bluerhine.com
EMAIL;WORK;X-EDIT=0;X-POS=142,61,26,234;CHARSET=utf-8:oman#onn.bluerhine.com
EXCHANGEDATE:2019-06-16
EXCHANGEDATE:2019-06-16
AUTHOR:IntSig-iOS-iPhone
ORG;WORK;X-EDIT=0;X-POS=0,0,0,0,59,29,33,295,0,0,0,0;CHARSET=utf-8:;Business Development Manaus)r;
TEL;WORK;X-EDIT=0;X-POS=88,107,23,142;CHARSET=utf-8:+96897641700
TEL;WORK;X-EDIT=0;X-POS=332,133,28,182;CHARSET=utf-8:+96822022247
TEL;WORK;X-EDIT=0;X-POS=328,36,27,92;CHARSET=utf-8:24796647
END:VCARD
Code:
Regex regex = new Regex(#"(?<strElement>(FN)) (:(?<strFN>[^\r\n]*))", options);// For retrieving the First Name
Regex regex = new Regex(#"((?<strElement>(EMAIL)) (;*(?<strAttr>(HOME|WORK)))* (;(?<strPref>(PREF)))* (;[^:]*)* (:(?<strValue>[^\n\r]*)))");//for retrieving Email
I am not getting the exact regular expression formula required.

Here is a simple parser :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.IO;
namespace ConsoleApplication124
{
class Program
{
static void Main(string[] args)
{
string input =
"BEGIN:VCARD\n" +
"VERSION:2.1\n" +
"FN;CHARSET=utf-8:s James F ' Ernande.\n" +
"ADR;WORK;X-EDIT=0;X-POS=280,43,54,269,0,0,0,0;CHARSET=utf-8:;;P.O. Box No: 570, P. C-112, Ruwi Muscat, Sultanate Ofoman;;;;\n" +
"X-IS-TAKE-ADR;CHARSET=utf-8:23.62866567746918;58.26649072858852;\n" +
"N;X-EDIT=0;X-POS=33,89,29,178;CHARSET=utf-8:s;James F ' Ernande. ;;;\n" +
"EMAIL;WORK;X-EDIT=0;X-POS=116,59,26,237;CHARSET=utf-8:james#om.bluerhine.com\n" +
"EMAIL;WORK;X-EDIT=0;X-POS=142,61,26,234;CHARSET=utf-8:oman#onn.bluerhine.com\n" +
"EXCHANGEDATE:2019-06-16\n" +
"EXCHANGEDATE:2019-06-16\n" +
"AUTHOR:IntSig-iOS-iPhone\n" +
"ORG;WORK;X-EDIT=0;X-POS=0,0,0,0,59,29,33,295,0,0,0,0;CHARSET=utf-8:;Business Development Manaus)r;\n" +
"TEL;WORK;X-EDIT=0;X-POS=88,107,23,142;CHARSET=utf-8:+96897641700\n" +
"TEL;WORK;X-EDIT=0;X-POS=332,133,28,182;CHARSET=utf-8:+96822022247\n" +
"TEL;WORK;X-EDIT=0;X-POS=328,36,27,92;CHARSET=utf-8:24796647\n" +
"END:VCARD";
ParseVCF parseVCF = new ParseVCF(input);
}
}
public class ParseVCF
{
public string version { get; set; }
public List<string> data = new List<string>();
enum State
{
FIND_BEGIN,
GET_VERSION,
PROCESS_DATA,
FOUND_END
}
public ParseVCF(string input)
{
StringReader reader = new StringReader(input);
string line = "";
State state = State.FIND_BEGIN;
while(((line = reader.ReadLine()) != null) && (state != State.FOUND_END))
{
line = line.Trim();
if (line.Length > 0)
{
switch (state)
{
case State.FIND_BEGIN :
if (line.StartsWith("BEGIN:"))
{
state = State.GET_VERSION;
}
break;
case State.GET_VERSION :
string[] split = line.Split(new char[] { ':' });
version = split[1];
state = State.PROCESS_DATA;
break;
case State.PROCESS_DATA :
if(line.StartsWith("END"))
{
state = State.FOUND_END;
}
else
{
data.Add(line);
}
break;
}
}
}
}
}
}

Related

How to extract specific string from a text?

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Newtonsoft.Json;
namespace Rename_Files
{
public partial class Form1 : Form
{
string[] files;
public Form1()
{
InitializeComponent();
files = Directory.GetFiles(#"C:\Program Files (x86)\Steam\steamapps\common\King's Quest\Binaries\Win\Saved Games", "*.*", SearchOption.AllDirectories);
for(int i = 2; i < files.Length; i++)
{
string text = File.ReadAllText(files[i]);
int startPos = text.IndexOf("currentLevelName");
int length = text.IndexOf("currentLevelEntryDirection") - 3;
string sub = text.Substring(startPos, length);
}
}
private void Form1_Load(object sender, EventArgs e)
{
}
}
}
The part i want to extract is :
currentLevelName":"E1_WL1_FindBow_M","currentLevelEntryDirection"
This is a part of the file content :
m_ItemsEncodedJsons ArrayProperty None ! m_WhatLevelPlayerIsAtEncodedJson ArrayProperty O G {"currentLevelName":"E1_WL1_FindBow_M","currentLevelEntryDirection":8} & m_WhatCheckPointPlay
the way i'm trying now i'm getting exception because
System.ArgumentOutOfRangeException: 'Index and length must refer to a location within the string.
Parameter name: length'
startPos value is : 1613 and the value of length is 1653
so the exception is logic but i'm not sure yet how to extract the specific string out of the text.
Update :
this is almost working :
int startPos = text.IndexOf("currentLevelName");
int length = text.IndexOf("currentLevelEntryDirection");
string sub = text.Substring(startPos, length - startPos);
the result in sub is :
"currentLevelName\":\"E1_WL1_HangingBedsA_M\",\""
but i want that sub will contain this :
currentLevelName"E1_WL1_HangingBedsA_M\"
optional without the two "" either and maybe to add _
currentLevelName_"E1_WL1_HangingBedsA_M\"
or
currentLevelName_E1_WL1_HangingBedsA_M\
The problem you are facing is indeed this one:
How to extract the content with specific pattern from a String?
In this case, you can use Regular Expression to extract the content you want.
Given the following text:
m_ItemsEncodedJsons ArrayProperty None ! m_WhatLevelPlayerIsAtEncodedJson ArrayProperty O G {"currentLevelName":"E1_WL1_FindBow_M","currentLevelEntryDirection":8} & m_WhatCheckPointPlay
By using this Regex pattern:
string pattern = #"""currentLevelName"":"".*"",""currentLevelEntryDirection"":\d+";
You will be able to extract the following content:
"currentLevelName":"E1_WL1_FindBow_M","currentLevelEntryDirection":8
Here is the code snippet in C#:
using System;
using System.Text.RegularExpressions;
public class Example
{
public static void Main()
{
// this is the original text
string input = #"m_ItemsEncodedJsons ArrayProperty None ! m_WhatLevelPlayerIsAtEncodedJson ArrayProperty O G {""currentLevelName"":""E1_WL1_FindBow_M"",""currentLevelEntryDirection"":8} & m_WhatCheckPointPlay";
// this is the pattern you are looking for
string pattern = #"""currentLevelName"":"".*"",""currentLevelEntryDirection"":\d+";
RegexOptions options = RegexOptions.Multiline;
foreach (Match m in Regex.Matches(input, pattern, options))
{
Console.WriteLine("'{0}' found at index {1}.", m.Value, m.Index);
}
}
}
One of the reasons you should use Regex in this case is that, if the value of currentLevelEntryDirection is not single-digit, e.g. 8123, the above code snippet can still be able to extract the correct value.
You can also find the above example and edit it here: https://regex101.com/r/W4ihuk/3
Furthermore, you can extract the property names and values by using capturing group. For example:
string pattern = #"""(currentLevelName)"":""(.*)"",""(currentLevelEntryDirection)"":(\d+)";
You can extract the following data:
currentLevelName, E1_WL1_FindBow_M, currentLevelEntryDirection, 8 and you can get the values by looping all the Match objects.
it seems the content is separated by a space delimiter. and the positions are fixed.
If so, you could do something like :
var splitted = text.Split(' ');
var json = splitted[8]; // this is the json part in the content;
However, since we don't know wither the content might change or not. You can still use this :
var startPos = text.IndexOf('{');
var endPos = text.IndexOf('}') + 1;
var json = text.Substring(startPos, endPos - startPos);
This would extract the Json part of the file. Now, you can implement a json model that will be used to deserialize this json like this :
using System.Text.Json;
using System.Text.Json.Serialization;
public class JsonModel
{
[JsonPropertyName("currentLevelName")]
public string? CurrentLevelName { get; set; }
[JsonPropertyName("currentLevelEntryDirection")]
public int CurrentLevelEntryDirection { get; set; }
}
With that we can do :
var result = JsonSerializer.Deserialize<JsonModel>(json);
var leveName = result.CurrentLevelName;
private string FindCurrentLevelName(string MyString)
{
var FirstSplit = MyString.Split(new char[] { '{' },
StringSplitOptions.RemoveEmptyEntries);
if (FirstSplit.Length != 2)
{
return "";
}
var SecondSplit = FirstSplit[1].Split(new char[] { '}' },
StringSplitOptions.RemoveEmptyEntries);
if (SecondSplit.Length != 2)
{
return "";
}
var FinalSplit = SecondSplit[0].Split(new char[] { '"' },
StringSplitOptions.RemoveEmptyEntries);
if (FinalSplit.Length != 6)
{
return "";
}
return FinalSplit[2];
}
To get the specific string pattern in a non-JSON format data string
Use the regex to get the stirng and operate it will be good I thought.
By using the regex pattern: "currentLevelName":"\w+"
in your example content, your will get: "currentLevelName":"E1_WL1_HangingBedsA_M"
Then use the result to create or replace your file name.
the code below will get the savedGame001.txt's content and extract the currentLevelName block, then create a new file whcih the name is in this format: [filename]_[theCurrentLevelName]
using System.Text.RegularExpressions;
// your file path
string filePath = #"C:\Users\a0204\Downloads";
// your file name
string fileName = #"savedGame001.txt";
// read file content
string stringContent = string.Empty;
stringContent = System.IO.File.ReadAllText(filePath + "\\" + fileName);
// Get the mathced string By regex => "currentLevelName":"\w+"
var regex = new Regex("\"currentLevelName\":\"\\w+\"");
Match matched = regex.Match(stringContent);
string matchedString = matched.Value;
// Get the string below the colon
int colonPosition = matchedString.IndexOf(":");
string value = matchedString.Substring(colonPosition + 1);
value = value.Replace("\"", string.Empty);
// remove the .txt and add the matched string to file name
fileName = fileName.Remove(fileName.Length - 4, 4);
string newFileName = fileName + "_" + value;
// check the new file name
Console.WriteLine(newFileName);
// write content to new file name
FileStream fileStream = File.Create(filePath + "\\" + newFileName);
fileStream.Dispose();
File.WriteAllText(filePath + "\\" + newFileName, stringContent);
Console.ReadLine();
PS: the code was written by .NET6 console app

Read the flat file,group and write to file(Add special Characters as '*' in Empty Space)

E2739158012008-10-01O9918107NPF7547379999010012008-10-0100125000000
E2739158PU0000-00-00 010012008-10-0100081625219
E3180826011985-01-14L9918007NPM4927359999010011985-01-1400005620000
E3180826PU0000-00-00 020011985-01-14000110443500021997-01-1400000518799
E3292015011985-01-16L9918007NPM4927349999010011985-01-1600003623300
I have this flat file and I need to group this based on the 2nd position to 8th position
example(2739158/3180826/3292015) and write to another flat file.
So the data Starting with 'E' should Repeat in the single line along with that group field(2nd to 8th Position in the start) and I should take the 9th Position after 'E'
Also I need to replace Empty space with ('*' star)
For example
1st Line
2739158**E**012008-10-01O9918107NPF7547379999010012008-10-0100125000000*****E**012008-10-01O9918107NPF7547379999010012008-10-0100125000000
2nd Line
3180826**E**011985-01-14L9918007NPM4927359999010011985-01-1400005620000**E**011985-01-14L9918007NPM4927359999010011985-01-140000562000**E**011985-01-14L9918007NPM4927359999010011985-01-140000562000***
3rd Line
3292015**E**011985-01-16L9918007NPM4927349999010011985-01-1600003623300****
Can we do this in Stream reader c#, please?
Any help would be highly appreciated.The file size is more than 285 MB so it it good to read through Stream Reader?
Thanks
#jdweng: thanks very much for your input. i tried somehow without grouping and it works as expected.Thanks everyone who tried to solve the issue.
string sTest= string.Empty; List<SortLines> lines = new List<SortLines>();
List<String> FinalLines = new List<String>();
using (StreamReader sr = new StreamReader(#"C:\data\Input1.txt))
{
sr.ReadLine();
string line = "";
while (!sr.EndOfStream)
{
line = sr.ReadLine();
//line = line.Trim();
if (line.Length > 0)
{
line = line.Replace(" ", "*");
SortLines newLine = new SortLines()
{
key = line.Substring(1, 7),
line = line
};
if (sTest != newLine.key)
{
//Add the Line Items to String List
sOuterLine = sTest + sOneLine;
FinalLines.Add(sOuterLine);
string sFinalLine = newLine.line.Remove(1, 7);
string snewLine = newLine.key + sFinalLine;
sTest = snewLine.Substring(0, 7);
//To hold the data for the 1st occurence
sOtherLine = snewLine.Remove(0, 7);
bOtherLine = true;
string sKey = newLine.key;
lines.Add(newLine);
}
else if (sTest == newLine.key)
{
string sConcatLine = String.Empty;
string sFinalLine = newLine.line.Remove(1, 7);
//Check if 1st Set
if (bOtherLine == true)
{
sOneLine = sOtherLine + sFinalLine;
bOtherLine = false;
}
//If not add subsequent data
else
{
sOneLine = sOneLine + sFinalLine;
}
//Check for the last line in the flat file
if (sr.Peek() == -1)
{
sOuterLine = sTest + sOneLine;
FinalLines.Add(sOuterLine);
}
}
}
}
}
//Remove the Empty List
FinalLines.RemoveAll(x => x == "");
StreamWriter srWriter = new StreamWriter(#"C:\data\test.txt);
foreach (var group in FinalLines)
{
srWriter.WriteLine(group);
}
srWriter.Flush();
srWriter.Close();
Try code below :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace ConsoleApplication1
{
class Program
{
const string INPUT_FILENAME = #"c:\temp\test.txt";
const string OUTPUT_FILENAME = #"c:\temp\test1.txt";
static void Main(string[] args)
{
List<SortLines> lines = new List<SortLines>();
StreamReader reader = new StreamReader(INPUT_FILENAME);
string line = "";
while ((line = reader.ReadLine()) != null)
{
line = line.Trim();
if (line.Length > 0)
{
line = line.Replace(" ", "*");
SortLines newLine = new SortLines() { key = line.Substring(2, 7), line = line };
lines.Add(newLine);
}
}
reader.Close();
var groups = lines.GroupBy(x => x.key);
StreamWriter writer = new StreamWriter(OUTPUT_FILENAME);
foreach (var group in groups)
{
foreach (SortLines sortLine in group)
{
writer.WriteLine(sortLine.line);
}
}
writer.Flush();
writer.Close();
}
}
public class SortLines : IComparable<SortLines>
{
public string line { get; set; }
public string key { get; set; }
public int CompareTo(SortLines other)
{
return key.CompareTo(other);
}
}
}

Taking multiple substrings from a single line in a .txt file in C#

Part of a class assignment I'm working on requires me to take isolate certain parts of a "students" info from a .txt file such as last name, first name, and gpa. While I can get the last name to appear properly, going beyond that is iffy, first names will be cut off or go to the middle initial seemingly randomly. I need help with having consistent cut off points based on markers (apostrophes) in the lines.
this is a sample of the .txt file Students2 which is located in the program's Bin Debug
(LIST (LIST 'Abbott 'Ashley 'J ) '8697387888 'ajabbott#mail.usi.edu 2.3073320999676614 )
(LIST (LIST 'Abbott 'Bradley 'M ) 'NONE 'bmabbott#mail.usi.edu 3.1915725161177115 )
(LIST (LIST 'Abbott 'Ryan 'T ) '8698689793 'rtabbott#mail.usi.edu 3.448215586562192 )
(LIST (LIST 'Abel 'Heather 'M ) '8698689386 'hmabel#mail.usi.edu 3.2517764202656974 )
Hopefully what I meant by markers makes sense, and the info is fake if anyone wondered.
The following is my current code, some of which was provided in an example.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
namespace ConsoleApplication61
{
class Program
{
static void Main(string[] args)
{
StreamReader inFile;
string inLine;
if (File.Exists("Students2.txt"))
{
try
{
using (StreamWriter Malachi = File.AppendText("Students2.txt"))
{
Malachi.WriteLine("(LIST (LIST 'Constant 'Malachi 'J ) '1832878847 'mconstant#mail.usi.edu 4.0000000000000000 )");
}
inFile = new StreamReader("Students2.txt");
while ((inLine = inFile.ReadLine()) != null)
{
int start = inLine.IndexOf("'");
if (start >= 0)
{
inLine = inLine.Substring(start);
int end = inLine.IndexOf(" ");
string lastname = inLine.Substring(0, end);
int endTwo = inLine.IndexOf(" ");
string firstname = inLine.Substring(end, endTwo);
int endThree = inLine.IndexOf(" ");
string email = inLine.Substring(endTwo, endThree);
Console.WriteLine( lastname + firstname );
}
}
}
catch (System.IO.IOException exc)
{
Console.WriteLine("Error");
}
}
}
}
}
Again I'd like to know what I'm doing wrong in regards to cutting off at specific points. Any and all help is greatly appreciated.
you can use the split function and replace function to get what you are looking for something like this
string test = "(LIST (LIST 'Constant 'Malachi 'J ) '1832878847 'mconstant#mail.usi.edu 4.0000000000000000 )";
test = test.Replace(")","");
string[] abc = test.Split(new string[] { "'" }, StringSplitOptions.None);
Console.WriteLine("Last Name =" + abc[1]);
Console.WriteLine("First Name =" + abc[2]);
Console.WriteLine("Middle Initial =" + abc[3]);
Console.WriteLine("Email gpa =" + abc[abc.Length-1]);
UPDATE
In case there is no apostrophe for gpa you can get those values as below, just replace the last line with this
Console.WriteLine("Email =" + (abc[abc.Length-1]).Split(' ')[0]);
Console.WriteLine("gpa =" + (abc[abc.Length-1]).Split(' ')[1]);
Here is a fiddle for it https://dotnetfiddle.net/vJYLXW
you need to update inLine every time you take off substring like -
int start = inLine.IndexOf("'");
if (start >= 0)
{
inLine = inLine.Substring(start);
int end = inLine.IndexOf(" ");
string lastname = inLine.Substring(0, end);
inLine = inLine.Substring(end + 1);
int endTwo = inLine.IndexOf(" ");
string firstname = inLine.Substring(end, endTwo);
inLine = inLine.Substring(endTwo + 1);
int endThree = inLine.IndexOf(" ");
string email = inLine.Substring(endTwo, endThree);
.
.
}
and so on.....
OR you take find next space after end point of first string like this -
int start = inLine.IndexOf("'");
if (start >= 0)
{
inLine = inLine.Substring(start);
int end = inLine.IndexOf(" ");
string lastname = inLine.Substring(0, end);
int endTwo = inLine.IndexOf(' ', end + 1);
string firstname = inLine.Substring(end, endTwo - end);
int endThree = inLine.IndexOf(' ', endTwo + 1);
string middleinitial = inLine.Substring(endTwo, endThree - endTwo);
endThree += 2; // to escape ')' after middle initial
int endFour = inLine.IndexOf(' ', endThree + 1);
string phone = inLine.Substring(endThree, endFour - endThree);
int endFive = inLine.IndexOf(' ', endFour + 1);
string email = inLine.Substring(endFour, endFive - endFour);
int endSix = inLine.IndexOf(' ', endFive + 1);
string gpa = inLine.Substring(endFive, endSix - endFive);
Console.WriteLine("Last Name - " + lastname);
Console.WriteLine("First Name - " + firstname);
Console.WriteLine("Middle Initial - " + middleinitial);
Console.WriteLine("Phone - " + phone);
Console.WriteLine("Email - " + email);
Console.WriteLine("GPA - " + gpa);
}
But I would recommend string split option. Read about String.Split Method
while ((inLine = inFile.ReadLine()) != null)
{
var splits = inLine.Split(new[] { ' ', '\'' }, StringSplitOptions.RemoveEmptyEntries);
if (splits.Length > 0)
{
Console.WriteLine("Last Name - " + splits[2]);
Console.WriteLine("First Name - " + splits[3]);
Console.WriteLine("Middle Initial - " + splits[4]);
Console.WriteLine("Phone - " + splits[6]);
Console.WriteLine("Email - " + splits[7]);
Console.WriteLine("GPA - " + splits[8]);
}
Console.WriteLine("------------------------------------------------------");
}
It is much easier to get the desired fields with regexp:
Regex rPattern= new Regex(#"\'([^'\s]+)[\'\s]+([^'\s]+)[\'\s]+([^'\s]+)[\'\s]+\)[\'\s]+([^'\s]+)[\'\s]+([^'\s]+)[\'\s]+([^'\s]+)");
....
Match m = rPattern.Match(inLine );
if(m.Success)
{
string lastname = m.Groups[1].Value;
string firstname = m.Groups[2].Value;
string middlename = m.Groups[3].Value;
string phone = m.Groups[4].Value;
string email = m.Groups[5].Value;
string somenumber = m.Groups[6].Value;
}
Your code can be something like this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
//PTK: don't forget include following line. IT'S IMPORTANT !!!
using System.Text.RegularExpressions;
namespace ConsoleApplication61
{
class Program
{
static void Main(string[] args)
{
StreamReader inFile;
string inLine;
//PTK: patern for your fields
Regex rPattern= new Regex(#"\'([^'\s]+)[\'\s]+([^'\s]+)[\'\s]+([^'\s]+)[\'\s]+\)[\'\s]+([^'\s]+)[\'\s]+([^'\s]+)[\'\s]+([^'\s]+)");
if (File.Exists("Students2.txt"))
{
try
{
using (StreamWriter Malachi = File.AppendText("Students2.txt"))
{
Malachi.WriteLine("(LIST (LIST 'Constant 'Malachi 'J ) '1832878847 'mconstant#mail.usi.edu 4.0000000000000000 )");
}
inFile = new StreamReader("Students2.txt");
while ((inLine = inFile.ReadLine()) != null)
{
//PTK: match the current line with the pattern
Match m = rPattern.Match(inLine );
if(m.Success)
{
string lastname = m.Groups[1].Value;
string firstname = m.Groups[2].Value;
string middlename = m.Groups[3].Value;
string phone = m.Groups[4].Value;
string email = m.Groups[5].Value;
string somenumber = m.Groups[6].Value;
Console.WriteLine( lastname + firstname );
}
}
}
catch (System.IO.IOException exc)
{
Console.WriteLine("Error");
}
}
}
}
}
You can see working demo here: https://dotnetfiddle.net/FrU4l5

Change the name of headers in CSV file using CSVHelper in C#

I am using CSV Helper library to produce CSV files for the user to
to populate and upload into the system. My issue is that the WriteHeader method just writes the attributes of a class with names like "PropertyValue", which is not user friendly. Is there a method I can use to make the text produced user friendly but is still able to successfully map the class to the files data?
My code looks like the following:
public ActionResult UploadPropertyCSV(HttpPostedFileBase file)
{
List<PropertyModel> properties = new List<PropertyModel>();
RIMEDb dbContext = new RIMEDb();
bool success = false;
foreach (string requestFiles in Request.Files)
{
if (file != null && file.ContentLength > 0 && file.FileName.EndsWith(".csv"))
{
using(StreamReader str = new StreamReader(file.InputStream))
{
using(CsvHelper.CsvReader theReader = new CsvHelper.CsvReader(str))
{
while (theReader.Read())
{
RIMUtil.PropertyUploadCSVRowHelper row = new RIMUtil.PropertyUploadCSVRowHelper()
{
UnitNumber = theReader.GetField(0),
StreetNumber = theReader.GetField(1),
StreetName = theReader.GetField(2),
AlternateAddress = theReader.GetField(3),
City = theReader.GetField(4)
};
Property property = new Property();
property.UnitNumber = row.UnitNumber;
property.StreetNumber = row.StreetNumber;
property.StreetName = row.StreetName;
property.AlternateAddress = row.AlternateAddress;
property.City = dbContext.PostalCodes.Where(p => p.PostalCode1 == row.PostalCode).FirstOrDefault().City;
dbContext.Properties.Add(property);
try
{
dbContext.SaveChanges();
success = true;
}
catch(System.Data.Entity.Validation.DbEntityValidationException ex)
{
success = false;
RIMUtil.LogError("Ptoblem validating fields in database. Please check your CSV file for errors.");
}
catch(Exception e)
{
RIMUtil.LogError("Error saving property to database. Please check your CSV file for errors.");
}
}
}
}
}
}
return Json(success);
}
I'm wondering if theres some metadata tag or something I can put on top of each attribute in my PropertyUploadCSVRowHelper class to put the text I want produced in the file
Thanks in advance
Not sure if this existed 2 years ago but now, we can change the property/column name by using the following attribute function:
[CsvHelper.Configuration.Attributes.Name("Column/Field Name")]
Full code:
using CsvHelper;
using System.Collections.Generic;
using System.IO;
namespace Test
{
class Program
{
class CsvColumns
{
private string column_01;
[CsvHelper.Configuration.Attributes.Name("Column 01")] // changes header/column name Column_01 to Column 01
public string Column_01 { get => column_01; set => column_01 = value; }
}
static void Main(string[] args)
{
List<CsvColumns> csvOutput = new List<CsvColumns>();
CsvColumns rows = new CsvColumns();
rows.Column_01 = "data1";
csvOutput.Add(rows);
string filename = "test.csv";
using (StreamWriter writer = File.CreateText(filename))
{
CsvWriter csv = new CsvWriter(writer);
csv.WriteRecords(csvOutput);
}
}
}
}
This might not be answering your question directly as you said you wanted to use csvhelper, but if you're only writing small size files (this is a simple function that I use to generate csv. Note, csvhelper will be much better for larger files as this is just building a string and not streaming the data.
Just customise the columns array in the code below variable to suit your needs.
public string GetCsv(string[] columns, List<object[]> data)
{
StringBuilder CsvData = new StringBuilder();
//add column headers
string[] s = new string[columns.Length];
for (Int32 j = 0; j < columns.Length; j++)
{
s[j] = columns[j];
if (s[j].Contains("\"")) //replace " with ""
s[j].Replace("\"", "\"\"");
if (s[j].Contains("\"") || s[j].Contains(" ")) //add "'s around any string with space or "
s[j] = "\"" + s[j] + "\"";
}
CsvData.AppendLine(string.Join(",", s));
//add rows
foreach (var row in data)
{
for (int j = 0; j < columns.Length; j++)
{
s[j] = row[j] == null ? "" : row[j].ToString();
if (s[j].Contains("\"")) //replace " with ""
s[j].Replace("\"", "\"\"");
if (s[j].Contains("\"") || s[j].Contains(" ")) //add "'s around any string with space or "
s[j] = "\"" + s[j] + "\"";
}
CsvData.AppendLine(string.Join(",", s));
}
return CsvData.ToString();
}
Here is a fiddle example of how to use it: https://dotnetfiddle.net/2WHf6o
Good luck.

How to Serialize a list of objects

using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows.Forms;
using System.Xml.Serialization;
namespace AppPrueba
{
public partial class Form1 : Form
{
ArrayList listaFilas = new ArrayList();
public Form1()
{
InitializeComponent();
}
List<Empleados> emp = new List<Empleados>();
List<Agenda> agen = new List<Agenda>();
static public void SerializeToXML(List<Agenda> agen)
{
XmlSerializer serializer = new XmlSerializer(typeof(List<Agenda>));
TextWriter textWriter = new StreamWriter(#"C:\agenda.xml");
serializer.Serialize(textWriter, agen);
textWriter.Close();
}
private void button1_Click(object sender, EventArgs e)
{
openFileDialog1.ShowDialog(this);
string strfilename = openFileDialog1.FileName;
txtPath.Text = strfilename;
if ((strfilename.Trim().Length > 0) && (File.Exists(strfilename)))
{
string[] readText = File.ReadAllLines(strfilename);
if (strfilename.EndsWith("Agenda.txt"))
{
lstLinesBeforeChange.Items.Clear();
foreach (string s in readText)
{
lstLinesBeforeChange.Items.Add(s);
}
}
else
{
lstLinesBeforeChange.Items.Clear();
foreach (string s in readText)
{
lstLinesBeforeChange.Items.Add(s);
}
}
}
}
private void btnModify_Click(object sender, EventArgs e)
{
string strfilename = txtPath.Text;
string[] readText = File.ReadAllLines(strfilename);
if (strfilename.EndsWith("Agenda.txt"))
{
lstLinesAfterChange.Items.Clear();
foreach (string s in readText)
{
int nroEmp = Convert.ToInt32(s.Substring(0, 4));
string nombre = s.Substring(4, 15);
string telef = s.Substring(19, 10);
string ciudad = s.Substring(29);
Agenda unAgenda = new Agenda();
unAgenda.NroEmp = nroEmp;
unAgenda.Nombre = nombre.TrimStart().TrimEnd();
unAgenda.Telefono = telef;
unAgenda.Localidad = ciudad;
agen.Add(unAgenda);
agen.Sort(delegate(Agenda a1, Agenda a2)
{
return a1.NroEmp.CompareTo(a2.NroEmp);
});
}
foreach (Agenda a in agen)
{
string agenOrd = a.NroEmp.ToString() + "\t" + a.Nombre + "\t" + a.Telefono + "\t" + a.Localidad;
lstLinesAfterChange.Items.Add(agenOrd);
}
}
else
{
lstLinesAfterChange.Items.Clear();
foreach (string s in readText)
{
string[] sSinBarra = s.Split('|');
int nroEmp = Convert.ToInt32(sSinBarra[0]);
string nombre = sSinBarra[1];
string posicion = sSinBarra[2];
int nroOficina = Convert.ToInt32(sSinBarra[3]);
int piso = Convert.ToInt32(sSinBarra[4]);
string fechaIng = sSinBarra[5];
int dia = Convert.ToInt32(fechaIng.Substring(0, 2));
int mes = Convert.ToInt32(fechaIng.Substring(2, 2));
int año = Convert.ToInt32(fechaIng.Substring(4, 4));
string fechaIngreso = dia + "/" + mes + "/" + año;
fechaIng = fechaIngreso;
Empleados unEmpleado = new Empleados();
unEmpleado.NroEmpleado1 = nroEmp;
unEmpleado.Nombre1 = nombre.TrimEnd().TrimStart();
unEmpleado.Posicion = posicion.TrimEnd().TrimStart();
unEmpleado.NroOficina = nroOficina;
unEmpleado.Piso = piso;
unEmpleado.FechaIngreso = fechaIngreso;
emp.Add(unEmpleado);
emp.Sort(delegate(Empleados e1, Empleados e2)
{
return e1.NroEmpleado1.CompareTo(e2.NroEmpleado1);
});
}
foreach (Empleados em in emp)
{
string empOrd = em.NroEmpleado1.ToString() + "\t" + em.Nombre1 + "\t" + em.Posicion + "\t" + em.NroOficina.ToString()
+ "\t" + em.Piso.ToString() + "\t" + em.FechaIngreso;
lstLinesAfterChange.Items.Add(empOrd);
}
}
}
private void btnSave_Click(object sender, EventArgs e)
{
//SaveFileDialog saveFileDialog1 = new SaveFileDialog();
//saveFileDialog1.ShowDialog();
//if (saveFileDialog1.FileName != "")
//{
// FileStream fs = (FileStream)saveFileDialog1.OpenFile();
// fs.Close();
//}
SerializeToXML(agen);
}
}
}
I have this, and i want to serialize to xml both lists :
List<Empleados> emp = new List<Empleados>();
List<Agenda> agen = new List<Agenda>();
I used SerializeToXML method that i found in other tutorial but when i run it an error shows up
"Error 1 Inconsistent accessibility: parameter type
'System.Collections.Generic.List' is less accessible
than method
'AppPrueba.Form1.SerializeToXML(System.Collections.Generic.List)' C:\Users\722825\Desktop\Santi
Cosas\AppPrueba\AppPrueba\Form1.cs 27 28 AppPrueba"
Thanks in advance if you can help me!
All the classes that you are trying to serialize to xml should be public. And for collection serialization you cannot use generics - either use untyped collections, like, ArrayList , or create a non-generic descendant class form List .
agen is private and SerializeToXML is public static. You need agen public
Your error says that the variabel List agen = new List(); needs to be public like this: public List agen = new List();

Categories