Related
How do i input integers from a file into a vector3 or a int variable?
This is my code what works for only string
using (var enviromentPos = new FileStream("enviromentPos.txt", FileMode.OpenOrCreate))
{
using(var input = new StreamReader(enviromentPos))
{
int line = "";
while ((line = input.ReadLine()) != null)
{
}
}
}
String line="";
List<int> foo = new List<int>()
while ((line = input.ReadLine()) != null)
{
int i=0;
if(int.TryParse(line,out i)) foo.Add(i);
}
will read line by line and add all lines which contain something int-parseable to the list as parsed int values
Once you have the code that reads your input:
String line = null;
var input = new List<int>();
while ((line = file.ReadLine()) != null)
{
int i = 0;
if( int.TryParse(line,out i))
{
input.Add(i);
}
}
You can either process the list afterwards:
var vectors = new List<Vector3>();
for (int index = 0; index < input.Count; index += 3)
{
vectors.Add(new Vector3(input[index], input[index+1], input[index+2]);
}
You would need to make sure that the input was a multiple of three by either truncating it or padding it.
Or you could process the input as you are reading, but then you'd need a counter so that you could execute the vectors.Add code every third value read from the file:
String line = null;
var input = new List<int>();
int count = 0;
var vectors = new List<Vector3>();
while ((line = file.ReadLine()) != null)
{
int i = 0;
if( int.TryParse(line,out i))
{
input.Add(i);
count++;
if (count % 3 == 0)
{
vectors.Add(new Vector3(input[count-2], input[count-1], input[count]);
}
}
}
I am trying to read the data in a text file which is separated by commas. My problem, is that one of my data pieces has a comma within it. An example of what the text file looks like is:
a, b, "c, d", e, f.
I want to be able to take the comma between c and d and change it to a semicolon so that I can still use the string.Split() method.
using (StreamReader reader = new StreamReader("file.txt"))
{
string line;
while ((line = reader.ReadLine ()) != null) {
bool firstQuote = false;
for (int i = 0; i < line.Length; i++)
{
if (line [i] == '"' )
{
firstQuote = true;
}
else if (firstQuote == true)
{
if (line [i] == '"')
{
break;
}
if ((line [i] == ','))
{
line = line.Substring (0, i) + ";" + line.Substring (i + 1, (line.Length - 1) - i);
}
}
}
Console.WriteLine (line);
}
I am having a problem. Instead of producing
a, b, "c; d", e, f
it is producing
a, b, "c; d"; e; f
It is replacing all of the following commas with semicolons instead of just the comma in the quotes. Can anybody help me fix my existing code?
Basically if you find a closing " you recognize it as it was an opening quote.
Change the line:
firstQuote = true;
to
firstQuote = !firstQuote;
and it should work.
You need to reset firstquote to false after you hit the second quote.
else if (firstQuote == true) {
if (line [i] == '"') {
firstquote = false;
break;
}
Here is a simple application to get the required result
static void Main(string[] args)
{
String str = "a,b,\"c,d\",e,f,\"g,h\",i,j,k,l,\"m,n,o\"";
int firstQuoteIndex = 0;
int secodQuoteIndex = 0;
Console.WriteLine(str);
bool iteration = false;
//String manipulation
//if count is even then count/2 is the number of pairs of double quotes we are having
//so we have to traverse count/2 times.
int count = str.Count(s => s.Equals('"'));
if (count >= 2)
{
firstQuoteIndex = str.IndexOf("\"");
for (int i = 0; i < count / 2; i++)
{
if (iteration)
{
firstQuoteIndex = str.IndexOf("\"", firstQuoteIndex + 1);
}
secodQuoteIndex = str.IndexOf("\"", firstQuoteIndex + 1);
string temp = str.Substring(firstQuoteIndex + 1, secodQuoteIndex - (firstQuoteIndex + 1));
firstQuoteIndex = secodQuoteIndex + 1;
if (count / 2 > 1)
iteration = true;
string temp2= temp.Replace(',', ';');
str = str.Replace(temp, temp2);
Console.WriteLine(temp);
}
}
Console.WriteLine(str);
Console.ReadLine();
}
Please feel free to ask in case of doubt
string line = "a,b,mc,dm,e,f,mk,lm,g,h";
string result =replacestr(line, 'm', ',', ';');
public string replacestr(string line,char seperator,char oldchr,char newchr)
{
int cnt = 0;
StringBuilder b = new StringBuilder();
foreach (char chr in line)
{
if (cnt == 1 && chr == seperator)
{
b[b.ToString().LastIndexOf(oldchr)] = newchr;
b.Append(chr);
cnt = 0;
}
else
{
if (chr == seperator)
cnt = 1;
b.Append(chr);
}
}
return b.ToString();
}
I have a file that is a SQL Server result set saved as a text file.
Here is a sample of what the file looks like:
RWS_DMP_ID RV1_DMP_NUM CUS_NAME
3192 3957 THE ACME COMPANY
3192 3957 THE ACME COMPANY
3192 3957 THE ACME COMPANY
I want to create a C# program that reads this file and creates the following table of data:
Field MaxSize
----- -------
RWS_DMP_ID 17
RV1_DMP_NUM 17
CUS_NAME 42
This is a list of the field names and their max length. The max length is the beginning of the field to the space right before the beginning of the next field.
By the way I don't care about code performance. This is seldom used file processing utility.
I solved this with the following code:
objFile = new StreamReader(strPath + strFileName);
strLine = objFile.ReadLine();
intLineCnt = 0;
while (strLine != null)
{
intLineCnt++;
if (intLineCnt <= 3)
{
if (intLineCnt == 1)
{
strWords = SplitWords(strLine);
intNumberOfFields = strWords.Length;
foreach (char c in strLine)
{
if (bolNewField == true)
{
bolFieldEnd = false;
bolNewField = false;
}
if (bolFieldEnd == false)
{
if (c == ' ')
{
bolFieldEnd = true;
}
}
else
{
if (c != ' ')
{
if (intFieldCnt < strWords.Length)
{
strProcessedData[intFieldCnt, 0] = strWords[intFieldCnt];
strProcessedData[intFieldCnt, 1] = (intCharCnt - 1).ToString();
}
intFieldCnt++;
intCharCnt = 1;
bolNewField = true;
}
}
if (bolNewField == false)
{
intCharCnt++;
}
}
strProcessedData[intFieldCnt, 0] = strWords[intFieldCnt];
strProcessedData[intFieldCnt, 1] = intCharCnt.ToString();
}
else if (intLineCnt == 3)
{
intLine2Cnt= 0;
intTotalLength = 0;
while(intLine2Cnt < intNumberOfFields)
{
intSize = Convert.ToInt32(strProcessedData[intLine2Cnt, 1]);
if (intSize + intTotalLength > strLine.Length)
{
intSize = strLine.Length - intTotalLength;
}
strField = strLine.Substring(intTotalLength, intSize);
strField = strField.Trim();
strProcessedData[intLine2Cnt, intLineCnt - 1] = strField;
intTotalLength = intTotalLength + intSize + 1;
intLine2Cnt++;
}
}
}
strLine = objFile.ReadLine();
}`enter code here`
I'm aware that this code is a complete hack job. I'm looking for a better way to solve this problem.
Is there a better way to solve this problem?
THanks
I'm not sure how memory efficient this is, but I think it's a bit cleaner (assuming your fields are tab-delimited):
var COL_DELIMITER = new[] { '\t' };
string[] lines = File.ReadAllLines(strPath + strFileName);
// read the field names from the first line
var fields = lines[0].Split(COL_DELIMITER, StringSplitOptions.RemoveEmptyEntries).ToList();
// get a 2-D array of the columns (excluding the header row)
string[][] columnsArray = lines.Skip(1).Select(l => l.Split(COL_DELIMITER)).ToArray();
// dictionary of columns with max length
var max = new Dictionary<string, int>();
// for each field, select all columns, and take the max string length
foreach (var field in fields)
{
max.Add(field, columnsArray.Select(row => row[fields.IndexOf(field)]).Max(col => col.Trim().Length));
}
// output per requirment
Console.WriteLine(string.Join(Environment.NewLine,
max.Keys.Select(field => field + " " + max[field])
));
void MaximumWidth(StreamReader reader)
{
string[] columns = null;
int[] maxWidth = null;
string line;
while ((line = reader.ReadLine()) != null)
{
string[] cols = line.Split('\t');
if (columns == null)
{
columns = cols;
maxWidth = new int[cols.Length];
}
else
{
for (int i = 0; i < columns.Length; i++)
{
int width = cols[i].Length;
if (maxWidth[i] < width)
{
maxWidth[i] = width;
}
}
}
}
// ...
}
Here is what I came up with. The big takeaway is to use the IndexOf string function.
class Program
{
static void Main(string[] args)
{
String strFilePath;
String strLine;
Int32 intMaxLineSize;
strFilePath = [File path and name];
StreamReader objFile= null;
objFile = new StreamReader(strFilePath);
intMaxLineSize = File.ReadAllLines(strFilePath).Max(line => line.Length);
//Get the first line
strLine = objFile.ReadLine();
GetFieldNameAndFieldLengh(strLine, intMaxLineSize);
Console.WriteLine("Press <enter> to continue.");
Console.ReadLine();
}
public static void GetFieldNameAndFieldLengh(String strLine, Int32 intMaxSize)
{
Int32 x;
string[] fields = null;
string[,] strFieldSizes = null;
Int32 intFieldSize;
fields = SplitWords(strLine);
strFieldSizes = new String[fields.Length, 2];
x = 0;
foreach (string strField in fields)
{
if (x < fields.Length - 1)
{
intFieldSize = strLine.IndexOf(fields[x + 1]) - strLine.IndexOf(fields[x]);
}
else
{
intFieldSize = intMaxSize - strLine.IndexOf(fields[x]);
}
strFieldSizes[x, 0] = fields[x];
strFieldSizes[x, 1] = intFieldSize.ToString();
x++;
}
Console.ReadLine();
}
static string[] SplitWords(string s)
{
return Regex.Split(s, #"\W+");
}
}
Okay so I've managed to read in a .txt file... now I'm trying to figure the best way to convert this information into a 2D array.
My text file (first two number provide height and width):
5
5
0,0,0,0,0
0,0,0,0,0
0,0,1,0,0
0,1,1,1,0
1,1,1,1,1
My C# / XNA:
string fileContents = string.Empty;
try
{
using (StreamReader reader = new StreamReader("Content/map.txt"))
{
fileContents = reader.ReadToEnd().ToString();
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
Now what I need to do next is define the size of the 2-dimensional map array and then populate the entry values... this is where I'm getting a bit stuck and have found various ways I can loop through the data but I don't think any of them have been terribly tidy.
What I've tried to do is have one loops which splits by newline... and then another loop which splits by comma delimiter.
Is this the best way to do it... or are there better alternatives?
It can be done with LINQ but that is only practical when you want (accept) an array-of-array, int[][] instead of a straight 2-dimensional int[,] .
int[][] data =
File.ReadLines(fileName)
.Skip(2)
.Select(l => l.Split(',').Select(n => int.Parse(n)).ToArray())
.ToArray();
The code below doesn't require the first to rows in your sample .CSV file:
5
5
I'd prefer it this way, but as a consequence, the code below reads the file twice. It would take a small modification use the first two rows in your sample instead.
private int[,] LoadData(string inputFilePath)
{
int[,] data = null;
if (File.Exists(inputFilePath))
{
Dictionary<string, int> counts = GetRowAndColumnCounts(inputFilePath);
int rowCount = counts["row_count"];
int columnCount = counts["column_count"];
data = new int[rowCount, columnCount];
using (StreamReader sr = File.OpenText(inputFilePath))
{
string s = "";
string[] split = null;
for (int i = 0; (s = sr.ReadLine()) != null; i++)
{
split = s.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
for (int j = 0; j < columnCount; j++)
{
data[i, j] = int.Parse(split[j]);
}
}
}
}
else
{
throw new FileDoesNotExistException("Input file does not exist");
}
return data;
}
private Dictionary<string, int> GetRowAndColumnCounts(string inputFilePath)
{
int rowCount = 0;
int columnCount = 0;
if (File.Exists(inputFilePath))
{
using (StreamReader sr = File.OpenText(inputFilePath))
{
string[] split = null;
int lineCount = 0;
for (string s = sr.ReadLine(); s != null; s = sr.ReadLine())
{
split = s.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
if (columnCount == 0)
{
columnCount = split.Length;
}
lineCount++;
}
rowCount = lineCount;
}
if (rowCount == 0 || columnCount == 0)
{
throw new FileEmptyException("No input data");
}
}
else
{
throw new FileDoesNotExistException("Input file does not exist");
}
Dictionary<string, int> counts = new Dictionary<string, int>();
counts.Add("row_count", rowCount);
counts.Add("column_count", columnCount);
return counts;
}
Here's the solution I've come up with which appears to work.
int[,] txtmap;
int height = 0;
int width = 0;
string fileContents = string.Empty;
try
{
using (StreamReader reader = new StreamReader("Content/map.txt"))
{
fileContents = reader.ReadToEnd().ToString();
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
string[] parts = fileContents.Split(new string[] { "\r\n" }, StringSplitOptions.None);
for (int i = 0; i < parts.Length; i++)
{
if (i == 0)
{
// set width
width = Int16.Parse(parts[i]);
}
else if (i == 1)
{
// set height
height = Int16.Parse(parts[i]);
txtmap = new int[width, height];
}
if (i > 1)
{
// loop through tiles and assign them as needed
string[] tiles = parts[i].Split(new string[] { "," }, StringSplitOptions.None);
for (int j = 0; j < tiles.Length; j++)
{
txtmap[i - 2, j] = Int16.Parse(tiles[j]);
}
}
}
How to split the CSV file in c sharp? And how to display this?
I've been using the TextFieldParser Class in the Microsoft.VisualBasic.FileIO namespace for a C# project I'm working on. It will handle complications such as embedded commas or fields that are enclosed in quotes etc. It returns a string[] and, in addition to CSV files, can also be used for parsing just about any type of structured text file.
Display where? About splitting, the best way is to use a good library to that effect.
This library is pretty good, I can recommend it heartily.
The problems using naïve methods is that the usually fail, there are tons of considerations without even thinking about performance:
What if the text contains commas
Support for the many existing formats (separated by semicolon, or text surrounded by quotes, or single quotes, etc.)
and many others
Import Micorosoft.VisualBasic as a reference (I know, its not that bad) and use Microsoft.VisualBasic.FileIO.TextFieldParser - this handles CSV files very well, and can be used in any .Net language.
read the file one line at a time, then ...
foreach (String line in line.Split(new char[] { ',' }))
Console.WriteLine(line);
This is a CSV parser I use on occasion.
Usage: (dgvMyView is a datagrid type.)
CSVReader reader = new CSVReader("C:\MyFile.txt");
reader.DisplayResults(dgvMyView);
Class:
using System.IO;
using System.Text.RegularExpressions;
using System.Windows.Forms;
public class CSVReader
{
private const string ESCAPE_SPLIT_REGEX = "({1}[^{1}]*{1})*(?<Separator>{0})({1}[^{1}]*{1})*";
private string[] FieldNames;
private List<string[]> Records;
private int ReadIndex;
public CSVReader(string File)
{
Records = new List<string[]>();
string[] Record = null;
StreamReader Reader = new StreamReader(File);
int Index = 0;
bool BlankRecord = true;
FieldNames = GetEscapedSVs(Reader.ReadLine());
while (!Reader.EndOfStream)
{
Record = GetEscapedSVs(Reader.ReadLine());
BlankRecord = true;
for (Index = 0; Index <= Record.Length - 1; Index++)
{
if (!string.IsNullOrEmpty(Record[Index])) BlankRecord = false;
}
if (!BlankRecord) Records.Add(Record);
}
ReadIndex = -1;
Reader.Close();
}
private string[] GetEscapedSVs(string Data)
{
return GetEscapedSVs(Data, ",", "\"");
}
private string[] GetEscapedSVs(string Data, string Separator, string Escape)
{
string[] Result = null;
int Index = 0;
int PriorMatchIndex = 0;
MatchCollection Matches = Regex.Matches(Data, string.Format(ESCAPE_SPLIT_REGEX, Separator, Escape));
Result = new string[Matches.Count];
for (Index = 0; Index <= Result.Length - 2; Index++)
{
Result[Index] = Data.Substring(PriorMatchIndex, Matches[Index].Groups["Separator"].Index - PriorMatchIndex);
PriorMatchIndex = Matches[Index].Groups["Separator"].Index + Separator.Length;
}
Result[Result.Length - 1] = Data.Substring(PriorMatchIndex);
for (Index = 0; Index <= Result.Length - 1; Index++)
{
if (Regex.IsMatch(Result[Index], string.Format("^{0}[^{0}].*[^{0}]{0}$", Escape))) Result[Index] = Result[Index].Substring(1, Result[Index].Length - 2);
Result[Index] = Result[Index].Replace(Escape + Escape, Escape);
if (Result[Index] == null) Result[Index] = "";
}
return Result;
}
public int FieldCount
{
get { return FieldNames.Length; }
}
public string GetString(int Index)
{
return Records[ReadIndex][Index];
}
public string GetName(int Index)
{
return FieldNames[Index];
}
public bool Read()
{
ReadIndex = ReadIndex + 1;
return ReadIndex < Records.Count;
}
public void DisplayResults(DataGridView DataView)
{
DataGridViewColumn col = default(DataGridViewColumn);
DataGridViewRow row = default(DataGridViewRow);
DataGridViewCell cell = default(DataGridViewCell);
DataGridViewColumnHeaderCell header = default(DataGridViewColumnHeaderCell);
int Index = 0;
ReadIndex = -1;
DataView.Rows.Clear();
DataView.Columns.Clear();
for (Index = 0; Index <= FieldCount - 1; Index++)
{
col = new DataGridViewColumn();
col.CellTemplate = new DataGridViewTextBoxCell();
header = new DataGridViewColumnHeaderCell();
header.Value = GetName(Index);
col.HeaderCell = header;
DataView.Columns.Add(col);
}
while (Read())
{
row = new DataGridViewRow();
for (Index = 0; Index <= FieldCount - 1; Index++)
{
cell = new DataGridViewTextBoxCell();
cell.Value = GetString(Index).ToString();
row.Cells.Add(cell);
}
DataView.Rows.Add(row);
}
}
}
I had got the result for my query. its like simple like i had read a file using io.file. and all the text are stored into a string. After that i splitted with a seperator. The code is shown below.
using System;
using System.Collections.Generic;
using System.Text;
namespace CSV
{
class Program
{
static void Main(string[] args)
{
string csv = "user1, user2, user3,user4,user5";
string[] split = csv.Split(new char[] {',',' '});
foreach(string s in split)
{
if (s.Trim() != "")
Console.WriteLine(s);
}
Console.ReadLine();
}
}
}
The following function takes a line from a CSV file and splits it into a List<string>.
Arguments:
string line = the line to split
string textQualifier = what (if any) text qualifier (i.e. "" or "\"" or "'")
char delim = the field delimiter (i.e. ',' or ';' or '|' or '\t')
int colCount = the expected number of fields (0 means don't check)
Example usage:
List<string> fields = SplitLine(line, "\"", ',', 5);
// or
List<string> fields = SplitLine(line, "'", '|', 10);
// or
List<string> fields = SplitLine(line, "", '\t', 0);
Function:
private List<string> SplitLine(string line, string textQualifier, char delim, int colCount)
{
List<string> fields = new List<string>();
string origLine = line;
char textQual = '"';
bool hasTextQual = false;
if (!String.IsNullOrEmpty(textQualifier))
{
hasTextQual = true;
textQual = textQualifier[0];
}
if (hasTextQual)
{
while (!String.IsNullOrEmpty(line))
{
if (line[0] == textQual) // field is text qualified so look for next unqualified delimiter
{
int fieldLen = 1;
while (true)
{
if (line.Length == 2) // must be final field (zero length)
{
fieldLen = 2;
break;
}
else if (fieldLen + 1 >= line.Length) // must be final field
{
fieldLen += 1;
break;
}
else if (line[fieldLen] == textQual && line[fieldLen + 1] == textQual) // escaped text qualifier
{
fieldLen += 2;
}
else if (line[fieldLen] == textQual && line[fieldLen + 1] == delim) // must be end of field
{
fieldLen += 1;
break;
}
else // not a delimiter
{
fieldLen += 1;
}
}
string escapedQual = textQual.ToString() + textQual.ToString();
fields.Add(line.Substring(1, fieldLen - 2).Replace(escapedQual, textQual.ToString())); // replace escaped qualifiers
if (line.Length >= fieldLen + 1)
{
line = line.Substring(fieldLen + 1);
if (line == "") // blank final field
{
fields.Add("");
}
}
else
{
line = "";
}
}
else // field is not text qualified
{
int fieldLen = line.IndexOf(delim);
if (fieldLen != -1) // check next delimiter position
{
fields.Add(line.Substring(0, fieldLen));
line = line.Substring(fieldLen + 1);
if (line == "") // final field must be blank
{
fields.Add("");
}
}
else // must be last field
{
fields.Add(line);
line = "";
}
}
}
}
else // if there is no text qualifier, then use existing split function
{
fields.AddRange(line.Split(delim));
}
if (colCount > 0 && colCount != fields.Count) // count doesn't match expected so throw exception
{
throw new Exception("Field count was:" + fields.Count.ToString() + ", expected:" + colCount.ToString() + ". Line:" + origLine);
}
return fields;
}
Problem: Convert a comma separated string into an array where commas in "quoted strings,,," should not be considered as separators but as part of an entry
Input:
String: First,"Second","Even,With,Commas",,Normal,"Sentence,with ""different"" problems",3,4,5
Output:
String-Array: ['First','Second','Even,With,Commas','','Normal','Sentence,with "different" problems','3','4','5']
Code:
string sLine;
sLine = "First,\"Second\",\"Even,With,Commas\",,Normal,\"Sentence,with \"\"different\"\" problems\",3,4,5";
// 1. Split line by separator; do not split if separator is within quotes
string Separator = ",";
string Escape = '"'.ToString();
MatchCollection Matches = Regex.Matches(sLine,
string.Format("({1}[^{1}]*{1})*(?<Separator>{0})({1}[^{1}]*{1})*", Separator, Escape));
string[] asColumns = new string[Matches.Count + 1];
int PriorMatchIndex = 0;
for (int Index = 0; Index <= asColumns.Length - 2; Index++)
{
asColumns[Index] = sLine.Substring(PriorMatchIndex, Matches[Index].Groups["Separator"].Index - PriorMatchIndex);
PriorMatchIndex = Matches[Index].Groups["Separator"].Index + Separator.Length;
}
asColumns[asColumns.Length - 1] = sLine.Substring(PriorMatchIndex);
// 2. Remove quotes
for (int Index = 0; Index <= asColumns.Length - 1; Index++)
{
if (Regex.IsMatch(asColumns[Index], string.Format("^{0}[^{0}].*[^{0}]{0}$", Escape))) // If "Text" is sourrounded by quotes (but ignore double quotes => "Leave ""inside"" quotes")
{
asColumns[Index] = asColumns[Index].Substring(1, asColumns[Index].Length - 2); // "Text" => Text
}
asColumns[Index] = asColumns[Index].Replace(Escape + Escape, Escape); // Remove double quotes ('My ""special"" text' => 'My "special" text')
if (asColumns[Index] == null) asColumns[Index] = "";
}
The output array is asColumns