So I had some assistance with this yesterday but now I needed to make a change and my change doesn't seem to work. Wanted to see if someone would help me with what I'm doing wrong.
So here is an example of the file read in
Now originally this was reading the FSD number of 0.264 then reading the first number in the first column of 3.4572 and the last number of that column. This worked fine. But now I know longer need that FSD number and I no longer need the first number 3.4572. Instead I need the first number that doesn't have 0.00 in the last column, and then the last number still. So this is what I have but it isn't grabbing anything at all, if (dataWithAvgVolts.Count() > 1) is skipped.
public partial class FrmTravelTime : Form
{
const string FSD__Line_Identifier = "Drilling Data";
const string Data_Start_Point_Identifier = "AVG_VOLTS";
const string Spark_Point_Identifier = "0.00";
static readonly char[] splitter = { ' ', '\t' };
public FrmTravelTime()
{
InitializeComponent();
}
private void btnCalculate_Click(object sender, EventArgs e)
{
foreach (DataGridViewRow row in DGV_Hidden.Rows)
{
FileInfo info = new FileInfo();
{
var lines = File.ReadAllLines(row.Cells["colfilelocation"].Value.ToString());
var fsdLine = lines.FirstOrDefault(line => line.Contains(FSD__Line_Identifier));
var dataWithAvgVolts = lines.SkipWhile(line => line.Contains(Data_Start_Point_Identifier + Spark_Point_Identifier + FSD__Line_Identifier)).ToList();
if (dataWithAvgVolts.Count() > 1)
{
var data = dataWithAvgVolts[1].Split(splitter);
info.startvalue = Convert.ToDouble(data[0]);
data = dataWithAvgVolts[dataWithAvgVolts.Count - 1].Split(splitter);
info.endvalue = Convert.ToDouble(data[0]);
}
info.finalnum = info.startvalue - info.endvalue;
}
}
}
public class FileInfo
{
public double startvalue;
public double endvalue;
public double firstnum;
public double finalnum;
}
So you see here the first line that finally does not have 0.00 is
3.0164 7793 1 0 0.159 0.02
So my info.startvalue will be 3.0164
This goes down a good 100ish lines until the last line of
2.7182 8089 0 0 0.015 22.19
So my info.endvalue should be 2.7182
#Amit
var lines = File.ReadAllLines(row.Cells["colfilelocation"].Value.ToString());
var fsdLine = lines.FirstOrDefault(line => line.Contains(FSD__Line_Identifier));
info.FSD = fsdLine.Substring(fsdLine.IndexOf(FSD_Identifier) + FSD_Identifier.Length, 7);
var dataWithAvgVolts = lines.SkipWhile(line => !line.Contains(Data_Start_Point_Identifier)).ToList();
var data = lines.Where(line => (!line.Contains(Data_Start_Point_Identifier) && !line.Contains(FSD__Line_Identifier) && !line.EndsWith("0.00"))).ToList();
if (data.Count > 1)
{
var line = data[0];
var tempdata = data[0].Split(splitter);
info.startvalue = Convert.ToDouble(tempdata[0]);
var thisdata = data[data.Count - 1].Split(splitter);
info.endvalue = Convert.ToDouble(thisdata[0]);
}
Your SkipWhile condition is incorrect.
line => !line.Contains(Data_Start_Point_Identifier + Spark_Point_Identifier + FSD__Line_Identifier)
Will mean AVG_VOLTS0.00Drilling Data . You are saying, skip the text file till the line does not contain AVG_VOLTS0.00Drilling Data. You do not have this is one line anywhere. So, basically, you seem to be skipping the entire file. Put up a else condition, that will work.
This line returns all rows which do not have "Drilling Data" word, "AVG_VOLTS" word, and do not end with "0.00".
var data = lines.Where(line=>(!line.Contains(Data_Start_Point_Identifier) && !line.Contains(FSD__Line_Identifier) && !line.EndsWith("0.00"))).ToList();
Then, take the rows, and process.
If condition can be
if (data.Count > 1)
{
var line = data[0];
var tempdata = data[0].Split(splitter);
info.startvalue = Convert.ToDouble(tempdata[0]);
var thisdata = data[data.Count - 1].Split(splitter);
info.endvalue = Convert.ToDouble(thisdata[0]);
}
Related
I am trying to build a file using a template. I am processing the file in a while loop line by line. The first section of the file, first 35 lines are header information. The infromation is surrounded by # signs. Take this string for example:
Field InspectionStationID 3 {"PVA TePla #WSM#", "sw#data.tool_context.TOOL_SOFTWARE_VERSION#", "#data.context.TOOL_ENTITY#"}
The expected output should be:
Field InspectionStationID 3 {"PVA TePla", "sw0.2.002", "WSM102"}
This header section uses a different mapping than the rest of the file so I wanted to parse the file line by line from top to bottom and use a different logic for each section so that I don't waste time parsing the entire file at once multiple times for different sections.
The logic uses two dictionaries populated from an xml file. Because the file has mutliple tables, I combined them in the two dictionaries like so:
var headerCdataIndexKeyVals = Dictionary<string, int>(){
{"data.tool_context.TOOL_SOFTWARE_VERSION", 1},
{"data.context.TOOL_ENTITY",0}
};
var headerCdataArrayKeyVals = new Dictionary<string, List<string>>();
var tool_contextCdataList = new list <string>{"HM654", "sw0.2.002"};
var contextCdataList = new List<string>{"WSM102"}
headerCdataArrayKeyVals.add("tool_context", tool_contextCdataList);
headerCdataArrayKeyVals.add("context", contextCdataList);
To help me map the values to their respective positions in the string in one go and without having to loop through multiple dictionaries.
I am using the following logic:
public static string FindSubsInDelimetersAndReturn(string str, char openDelimiter, char closeDelimiter, HeaderMapperData mapperData )
{
string newString = string.Empty;
// Stores the indices of
Stack <int> dels = new Stack <int>();
for (int i = 0; i < str.Length; i++)
{
var let = str[i];
// If opening delimeter
// is encountered
if (str[i] == openDelimiter && dels.Count == 0)
{
dels.Push(i);
}
// If closing delimeter
// is encountered
else if (str[i] == closeDelimiter && dels.Count > 0)
{
// Extract the position
// of opening delimeter
int pos = dels.Peek();
dels.Pop();
// Length of substring
int len = i - 1 - pos;
// Extract the substring
string headerSubstring = str.Substring(pos + 1, len);
bool hasKey = mapperData.HeaderCdataIndexKeyVals.TryGetValue(headerSubstring.ToUpper(), out int headerCdataIndex);
string[] headerSubstringSplit = headerSubstring.Split('.');
string headerCDataVal = string.Empty;
if (hasKey)
{
if (headerSubstring.Contains("CONTAINER.CONTEXT", StringComparison.OrdinalIgnoreCase))
{
headerCDataVal = mapperData.HeaderCdataArrayKeyVals[headerSubstringSplit[1].ToUpper() + '.' + headerSubstringSplit[2].ToUpper()][headerCdataIndex];
//mapperData.HeaderCdataArrayKeyVals[]
}
else
{
headerCDataVal = mapperData.HeaderCdataArrayKeyVals[headerSubstringSplit[1].ToUpper()][headerCdataIndex];
}
string strToReplace = openDelimiter + headerSubstring + closeDelimiter;
string sub = str.Remove(i + 1);
sub = sub.Replace(strToReplace, headerCDataVal);
newString += sub;
}
else if (headerSubstring == "WSM" && closeDelimiter == '#')
{
string sub = str.Remove(len + 1);
newString += sub.Replace(openDelimiter + headerSubstring + closeDelimiter, "");
}
else
{
newString += let;
}
}
}
return newString;
}
}
But my output turns out to be:
"\tFie\tField InspectionStationID 3 {\"PVA TePla#WSM#\", \"sw0.2.002\tField InspectionStationID 3 {\"PVA TePla#WSM#\", \"sw#data.tool_context.TOOL_SOFTWARE_VERSION#\", \"WSM102"
Can someone help understand why this is happening and how I can go about correcting it so I get the output:
Field InspectionStationID 3 {"PVA TePla", "sw0.2.002", "WSM102"}
Am i even trying to solve this the right way or is there a better cleaner way to do it? Btw if the key is not in the dictionary I replace it with empty string
I'm making a list of lines that need to be added to a .txt file (with tab delimitation). The text file needs to have a maximum of 500 entries plus a header.
Right now, I have this code, which is successfully iterating through my list and creating the text file with the header. If the file already exists, it appends the lines in my list without adding the header.
I can't quite figure out how to make a new file, add the header and add each line after my first file surpasses 500 entries.
Can you help me separate in 500 line files with headers? Thank you
This is the code I have so far:
var tab = new StringBuilder();
foreach (var line in textlinestoadd)
{
tab.AppendLine(line.ToString());
}
if (!File.Exists(textcsvpath))
{
string textheader = "Vendor\tDate\tInvoice\tPO\tTax\tTotal\tAcount\tType\tJobs\tClass" + Environment.NewLine;
File.WriteAllText(textcsvpath, textheader);
}
File.AppendAllLines(textcsvpath, textlinestoadd);
This seems like a good practice opportunity so I will leave the code part as exercise!
The basic idea is simple. Whenever you wrote 500 lines just reset and write to a new file
here is a high level pseudo code
Initialize StringBuilder sb
For each line do
Add line to sb
if line count == 500 then
save to file
reset sb
reset line count
update filename = next file
end if
End For
//writes the last chunk if # of lines is not multiple of 500
if line count is not 0 then
save to file
end if
I'd try something like this.
var tab = new StringBuilder();
int lineCount = 0;
string textheader = "Vendor\tDate\tInvoice\tPO\tTax\tTotal\tAcount\tType\tJobs\tClass" + Environment.NewLine;
if (File.Exists(textcsvpath)) {
FileStream fs = File.OpenRead(textcsvpath);
string[] fileContent = File.ReadAllLines(textcsvpath);
lineCount = fileContent.Length - 1; // assume the first line is the header
}
foreach (var line in textlinestoadd)
{
tab.AppendLine(line.ToString());
lineCount++;
if (lineCount > 0 && lineCount % 500 == 0)
{
if (!File.Exists(textcsvpath))
{
File.WriteAllText(textcsvpath, textheader);
}
File.AppendAllText(textcsvpath, tab.ToString());
tab.Clear();
textcsvpath = "some-new-file-name";
}
}
if (!File.Exists(textcsvpath))
{
File.WriteAllText(textcsvpath, textheader);
}
File.AppendAllText(textcsvpath, tab.ToString());
You'll need to do something to determine the new file name as you add a new file.
I'd do something like this:
const int limit = 500;
int iteration = 0;
string textHeader = "Vendor\tDate\tInvoice\tPO\tTax\tTotal\tAcount\tType\tJobs\tClass" + Environment.NewLine;
while(iteration * limit < textLinesToAdd.Count())
{
string fullPath = Path.Combine(filePath, $"{fileName}.{iteration}", extension);
IEnumerable<string> linesToAdd = textLinesToAdd.Skip(iteration++ * limit).Take(limit);
File.Create(fullPath);
File.WriteAllText(fullPath, textHeader);
File.AppendAllLines(fullPath, linesToAdd);
}
Define that filename as foo and the extension as bar, and you'll get a sequence of files called foo.0.bar, foo.1.bar, foo.2.bar and so on.
I'm assuming we want to create a file with the specified name, and then have some integer placed between the name and extension that increments every time a new file is created.
One way to do this would be to have a method that takes in a filePath string, a list of lines to write, a header string, and the maximum number of lines allowed per file. Then it could parse the directory of the file path, looking for a pattern related to the file name.
It would determine what the latest file name should be based on the contents of the directory and the number of lines in the last file that matches our pattern, then would write to that file until it was full, and then continue creating new files until the lines were all written.
Here's a sample class that can do that, where I added some helper methods to get a file's number, increment that number in the name, get the latest file from a directory, and write lines to the file. It also implements IComparer<string> so that we can pass it to OrderByDescending to easily sort the files we're interested in.
public class FileWriterHelper : IComparer<string>
{
public int Compare(string x, string y)
{
// Compare null
if (x == null) return y == null ? 0 : 1;
if (y == null) return -1;
// Compare count of parts split on '.'
var xParts = x.Split('.');
var yParts = y.Split('.');
if (xParts.Length < 3) return yParts.Length < 3 ? 0 : -1;
if (yParts.Length < 3) return 1;
// Compare numeric portion
int xNum, yNum;
if (int.TryParse(xParts[1], out xNum) &&
int.TryParse(yParts[1], out yNum))
{
return xNum.CompareTo(yNum);
}
// Unknown values
return string.Compare(x, y, StringComparison.Ordinal);
}
private static int? GetFileNumber(string fileName)
{
if (string.IsNullOrWhiteSpace(fileName)) return null;
var fileParts = fileName.Split('.');
int fileNum;
if (fileParts.Length < 3 || !int.TryParse(fileParts[1], out fileNum)) return null;
return fileNum;
}
private static string IncrementNumber(string fileName)
{
var number = GetFileNumber(fileName).GetValueOrDefault() + 1;
var fileParts = fileName.Split('.');
return $"{fileParts[0]}.{number}.{fileParts[fileParts.Length - 1]}";
}
private static string GetLatestFile(string filePath, int maxLines)
{
var fileDir = Path.GetDirectoryName(filePath);
var fileName = Path.GetFileNameWithoutExtension(filePath);
var fileExt = Path.GetExtension(filePath);
var latest = Directory.GetFiles(fileDir, $"{fileName}*{fileExt}")
.OrderByDescending(f => f, new FileWriterHelper())
.FirstOrDefault() ?? filePath;
return File.Exists(latest) && File.ReadAllLines(latest).Length >= maxLines
? Path.Combine(fileDir, IncrementNumber(Path.GetFileName(latest)))
: latest;
}
public static void WriteLinesToFile(string filePath, string header,
List<string> lines, int maxFileLines)
{
while ((lines?.Count ?? 0) > 0 && maxFileLines > 0)
{
var latestFile = GetLatestFile(filePath, maxFileLines);
if (!File.Exists(latestFile)) File.CreateText(latestFile).Close();
var lineCount = File.ReadAllLines(latestFile).Length;
if (lineCount == 0 && header != null)
{
File.WriteAllText(latestFile, string.Concat(header, Environment.NewLine));
lineCount = 1;
}
var numLinesToWrite = maxFileLines - lineCount;
File.AppendAllLines(latestFile, lines.Take(numLinesToWrite));
lines = lines.Skip(numLinesToWrite).ToList();
}
}
}
That was a bit of work, but now to use it is really simple:
private static void Main()
{
// Generate 5000 lines to write
var fileLines = Enumerable.Range(0, 5000).Select(i => $"Line number {i}").ToList();
// File path with base file name
var filePath = #"f:\public\temp\temp.csv";
// This should create 10 files
FileWriterHelper.WriteLinesToFile(filePath,
"HEADER: This should be the first line in each file.", fileLines, 500);
GetKeyFromUser("\nDone! Press any key to exit...");
}
If you run that once, it will create 10 files (because of the number of lines we're generating and the max number of lines per file we specified). And if you run it again, it will create 10 more, since we're using the same path and file name pattern, it recognizes the previous files that were in the location.
I'm sure it could use some work, but hopefully it's a start!
Someone here at works needs some calculations done from some numbers within a text file. I know how to do the calculation but I haven't worked with text file before. So I spent the night reading and wrote a little something for the first number I needed but it doesn't work.
So here is an example of the file.
So that first number that comes after FSD: 0.264 I need to read that number and save to a variable. The number will always be different per file. Then I need the first 3.4572 number read to a variable. and the last number of that column as well which you don't see here but for the example it can be the last one shown in the image of 3.3852 read and saved to a variable.
Maybe I'm making this much harder than it needs to be but this is what I was playing around with
public partial class FrmTravelTime : Form
{
string file = "";
public FrmTravelTime()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
DialogResult result = openFileDialog1.ShowDialog();
if (result == DialogResult.OK)
{
file = openFileDialog1.FileName;
}
}
private void button2_Click(object sender, EventArgs e)
{
var sLines = File.ReadAllLines(file)
.Where(s => !s.StartsWith("FSD:"))
.Where(s => !string.IsNullOrWhiteSpace(s))
.Select(s => new
{
SValue = Regex.Match(s, "(?<=S)[\\d.]*").Value,
})
.ToArray();
string Value = "";
for (int i = 0; i < sLines.Length; i++)
{
if (sLines[i].SValue == "")
{
Value = (sLines[i].SValue);
}
}
}
}
EDIT FOR #Ramankingdom
So if you see here all lines have an ending column of 0.00 until we get to
3.0164 7793 1 0 0.159 0.02
So what I'd like to do, is edit what we did to skip everything that has a column with 0.00 in that last column and make the first non 0.00 the info.firstvalue so in this case 3.0164
Now I tried this on my own and used
var data = lines.Where(line => (!line.Contains(Data_Start_Point_Identifier) && !line.Contains(FSD__Line_Identifier) && !line.EndsWith("0.00"))).ToList();
But that breaks info.startvalue and data = dataWithAvgVolts[dataWithAvgVolts.Count - 1].Split(splitter);
So I'd figured I'd check with you.
So I tried this but I keep getting invalid data error on info.startvalue
FileInfo info = new FileInfo();
var lines = File.ReadAllLines(row.Cells["colfilelocation"].Value.ToString());
var fsdLine = lines.FirstOrDefault(line =>
line.Contains(FSD__Line_Identifier));
info.FSD = fsdLine.Substring(fsdLine.IndexOf(FSD_Identifier) + FSD_Identifier.Length, 7);
var dataWithAvgVolts = lines.SkipWhile(line => !line.Contains(Data_Start_Point_Identifier)).ToList();
int index =1;
while(index < dataWithAvgVolts.Count())
{
var data = dataWithAvgVolts[index].Split(splitter);
if(data.Count() >1)
{
if(!Convert.ToDouble(data[data.Count()-1]) == 0)
{
//set start info
break;
}
}
index++;
}
the reverse loop you can run to set the end value
Here is the code
class Program
{
const string FSD_Identifier = "FSD:";
const string FSD__Line_Identifier = "Drilling Data";
const string Data_Start_Point_Identifier = "AVG_VOLTS";
static readonly char[] splitter = {' ','\t'};
static void Main(string[] args)
{
var result = GetFileInfo("c:\\sample.txt");
}
private static MyFileInfo GetFileInfo(string path)
{
MyFileInfo info = new MyFileInfo();
try
{
var lines = File.ReadAllLines(path);
var fsdLine = lines.FirstOrDefault(line => line.Contains(FSD__Line_Identifier));
info.FSD = fsdLine.Substring(fsdLine.IndexOf(FSD_Identifier) + FSD_Identifier.Length, 10); // take lenght you can specify or your own logic
var dataWithAvgVolts = lines.SkipWhile(line => !line.Contains(Data_Start_Point_Identifier)).ToList<string>();
if (dataWithAvgVolts.Count() > 1)
{
var data = dataWithAvgVolts[1].Split(splitter);
info.startvalue = Convert.ToDouble(data[0]);
data = dataWithAvgVolts[dataWithAvgVolts.Count-1].Split(splitter);
info.endvalue = Convert.ToDouble(data[0]);
}
}
catch (Exception ex)
{
//logging here
}
return info;
}
}
public class MyFileInfo
{
public string FSD;
public double startvalue;
public double endvalue;
}
I get the datas from an textfile. The File itself is already inserted by ReadAllLines and converted into a string - this works fine for me and I checked the content with a MessageBox.
The Textfile looks like this (This is just 1 line from about thousand):
3016XY1234567891111111ABCDEFGHIJKabcdef+0000001029916XY1111111123456789ABCDEFGHIJKabcdef+00000003801
Now these are 2 records and I need 2 datas from every record.
The "XY Number" - these are the first 16 digits AFTER "16XY" (16XY is always the same value)
Value from the example: XY1234567891111111
The "Price" - that is the 11 digits value after the plus. The last 2 digits specify the amount of Cent.
Value from the example: 102,99$
I Need both of this datas to be in the same row in my Datagrid View and also for all other Datas in this textfile.
All I can imagine is to write a code, which searchs the string after "16XY" and counts the next 16 digits - the same with the Price which searchs for a "plus" and counts the next 11 digits. Just in this case I would need to ignore the first line of the file because there are about 10x"+".
I tried several possibilities to search and count for that values but without any success right now. Im also not sure how to get the datas into the specific Datagrid View.
This is all I have to show at the moment:
List<List<string>> groups = new List<List<string>>();
List<string> current = null;
foreach (var line in File.ReadAllLines(path))
{
if (line.Contains("") && current == null)
current = new List<string>();
else if (line.Contains("") && current != null)
{
groups.Add(current);
current = null;
}
if (current != null)
current.Add(line);
}
//array
string output = string.Join(Environment.NewLine, current.ToArray());
//string
string final = string.Join("", output.ToCharArray());
MessageBox.Show(output);
Thanks in advance!
Create a class or struct to hold data
public class Data
{
String XYValue { set; get; }
Decimal Price { set; get; }
}
Then the reading logic (You might need to add some more checks):
string decimalSeperator = CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator;
List<Data> results = new List<Data>();
foreach(string line in File.ReadAllLines(path).Skip(1))
{
if (line == null)
continue;
int indexOfNextXY = 0;
while (true)
{
int indexOfXY = line.IndexOf("16XY", indexOfNextXY) + "16XY".Length;
int indexOfPlus = line.IndexOf("+", indexOfXY + 16) + "+".Length;
indexOfNextXY = line.IndexOf("16XY", indexOfPlus);
string xyValue = line.Substring(indexOfXY - 2, 18); // -2 to get the XY part
string price = indexOfNextXY < 0 ? line.Substring(indexOfPlus) : line.Substring(indexOfPlus, indexOfNextXY - indexOfPlus);
string intPart = price.Substring(0, price.Length - 2);
string decimalPart = price.Substring(price.Length - 2);
price = intPart + decimalSeperator + decimalPart;
results.Add(new Data (){ XYValue = xyValue, Price = Convert.ToDecimal(price) });
if (indexOfNextXY < 0)
break;
}
}
var regex = new Regex(#"\+(\d+)(\d{2})16(XY\d{16})");
var q =
from e in File.ReadLines("123.txt")
let find = regex.Match(e)
where find.Success
select new
{
price = double.Parse(find.Groups[1].Value) + (double.Parse(find.Groups[2].Value) / 100),
value = find.Groups[3]
};
dataGridView1.DataSource = q.ToList();
If you need the whole text file as string, you can manipulate it with .Split method.
The action will look something like this:
var values = final.Split(new string[] { "16XY" }, StringSplitOptions.RemoveEmptyEntries).ToList();
List <YourModel> models = new List<YourModel>();
foreach (var item in values)
{
if (item.IndexOf('+') > 0)
{
var itemSplit = item.Split('+');
if (itemSplit[0].Length > 15 &&
itemSplit[1].Length > 10)
{
models.Add(new YourModel(itemSplit[0].Substring(0, 16), itemSplit[1].Substring(0, 11)));
}
}
}
And you will need some model
public class YourModel
{
public YourModel(string xy, string price)
{
float forTest = 0;
XYNUMBER = xy;
string addForParse = string.Format("{0}.{1}", price.Substring(0, price.Length - 2), price.Substring(price.Length - 2, 2));
if (float.TryParse(addForParse, out forTest))
{
Price = forTest;
}
}
public string XYNUMBER { get; set; }
public float Price { get; set; }
}
After that you can bind it to your gridview.
Given that the "data pairs" are variable each line (and can get truncated to the next line), it is best to use File.ReadAllText() instead. This will give you a single string to work on, eliminating the truncation issue.
var data = File.ReadAllText(path);
Define a model to contain your data:
public class Item {
public string XYNumber { get; set; }
public double Price { get; set; }
}
You can then use regular expressions to find matches and store them in a list:
var list = List<Item>();
var regex = new Regex(#"(XY\d{16})\w+\+(\d{11})");
var match = regex.Match(data);
while (match.Success) {
var ps = match.Group[1].Captures[0].Value.Insert(9, ".");
list.Add(new Item {
XYNumber = match.Group[0].Captures[0].Value,
Price = Convert.ToDouble(ps)
});
match = match.NextMatch();
}
The list can also be used as a data source to a grid view:
gridView.DataSource = list;
Consider employing the Split method. From the example data, I notice there is "16XY" between each value. So something like this:
var data = "3016XY1234567891111111ABCDEFGHIJKabcdef+0000001029916XY1111111123456789ABCDEFGHIJKabcdef+00000003801";
var records = data.Split(new string[] { "16XY" }, StringSplitOptions.RemoveEmptyEntries);
Given the example data this will return the following array:
[0]: "30"
[1]: "1234567891111111ABCDEFGHIJKabcdef+00000010299"
[2]: "1111111123456789ABCDEFGHIJKabcdef+00000003801"
Now it will be easier to count characters in each string and give them meaning in your code.
So we know valuable data is separated by +. Lets split it further and fill a Dictionary<string, double>.
var parsed = new Dictionary<string, double>(records.Length - 1);
foreach (var pairX in records.Skip(1))
{
var fields = pairX.Split('+');
var cents = double.Parse(fields[1]);
parsed.Add(fields[0], cents / 100);
}
// Now you bind to the GridView
gv.DataSource = parsed;
And your 'GridView` declaration should look like this:
<asp:GridView ID="gv" runat="server" AutoGenerateColumns="false">
<Columns>
<asp:BoundField DataField="Key" HeaderText="ID" />
<asp:BoundField DataField="Value" HeaderText="Price" />
</Columns>
</asp:GridView>
I am using this code in my Web Api to get data from a csv file, and plug that data into a Item List.
private List<Item> ietms = new List<Item>();
public ItemRepository()
{
string filename = HttpRuntime.AppDomainAppPath + "App_Data\\items.csv";
var lines = File.ReadAllLines(filename).Skip(1).ToList();
for (int i = 0; i < lines.Count; i++)
{
var line = lines[i];
var columns = line.Split('$');
//get rid of newline characters in the middle of data lines
while (columns.Length < 9)
{
i += 1;
line = line.Replace("\n", " ") + lines[i];
columns = line.Split('$');
}
//Remove Starting and Trailing open quotes from fields
columns = columns.Select(c => { if (string.IsNullOrEmpty(c) == false) { return c.Substring(1, c.Length - 2); } return string.Empty; }).ToArray();
items.Add(new Item()
{
Id = int.Parse(columns[0]),
Name = columns[1],
Description = columns[2],
Price = string.IsNullOrEmpty(columns[3].Trim()) ? null : (double?)double.Parse(columns[3]),
Weight = columns[8],
PhotoUrl = columns[7],
Category=columns[9]
});
}
}
In the csv file one of the columns/value is structured like this:
Groups>Subgroup>item
or in some cases
MajorGroup|Groups>Subgroup>item
How do I pull out only the first value before the > or |, so that I would get the value as Groups in the first case and MajorGroup in the second, and store it in the Category property in the Item List, which is now just set to the entire value in column 9 which would return the whole string "Groups>Subgroup>item".
Add the following line before calling "Add item"
var temp = columns[9].Split('|', '>');
Then assign the category as follows.
Category = temp[0];
Based on: MSDN String Method Documentation
Did you mean something like this?
string data = "MajorGroup|Groups>Subgroup>item";
string groupOrCategory;
if (data.Contains('|'))
{
groupOrCategory = data.Substring(0, data.IndexOf('|'));
}
else
{
groupOrCategory = data.Substring(0, data.IndexOf('>'));
}
Console.WriteLine(groupOrCategory);