How to get data's from text file in c# - c#

I have a textile contains big amount of data ,first thing is i have to filter Leaf cell data which is scattered over there and here.For this first line i filtered is line beginning with ADD GCELL which contains primary data,next what i have to do is i have to get the related data from the same text file by using CELLID coming in the same ADD GCELL line.Related datas are coming in the line beggining with ADD GTRX and datas are FREQ , TRXNO , ISMAINBCCH ,.in nutshell CELLID is the common value for both line ADD GCELL and ADD GTRX. I have done few coding in c# , but i got stuck somewhere
Here is part of text file
...........................
...........................
ADD GCELL:CELLID=13, CELLNAME="NR_0702_07021_G1_A", MCC="424", MNC="02", LAC=6112, CI=7021, NCC=6, BCC=0, EXTTP=Normal_cell, IUOTP=Concentric_cell, ENIUO=ON, DBFREQBCCHIUO=Extra, FLEXMAIO=OFF, CSVSP=3, CSDSP=5, PSHPSP=4, PSLPSVP=6, BSPBCCHBLKS=1, BSPAGBLKSRES=4, BSPRACHBLKS=1, TYPE=GSM900_DCS1800, OPNAME="Tester", VIPCELL=NO
..............................
ADD GTRX:TRXID=11140, TRXNAME="T_RAK_JaziratHamra_G_702_7021_A-0", FREQ=99, TRXNO=0, CELLID=13, IDTYPE=BYID, ISMAINBCCH=YES, ISTMPTRX=NO, GTRXGROUPID=80;
Code i have done is
using (StreamReader sr = File.OpenText(filename))
{
while ((s = sr.ReadLine()) != null)
{
if (s.Contains("ADD GCELL:"))
{
s = s.Replace("ADD GCELL:", "");
string[] items = s.Split(',');
foreach (string str in items)
{
string[] str1 = str.Split('=');
if (str1[0] == "CELLID")
{
cellidnew = str1[1];
}
string fieldname = str1[0];
string value = str1[1].Replace(";", string.Empty).Replace("\"", string.Empty);
}
Getgtrxvalues(filename, ref cellname, ref cellidnew, ref Frequency, ref TRXNO ,ref ISMAINBCCH);
}
}
}
private static void Getgtrxvalues(string filename, ref string cellname, ref string cellid, ref int Frequency, ref int TRXNO ,ref bool ISMAINBCCH)
{
using (StreamReader sr = File.OpenText(filename))
{
while ((s = sr.ReadLine()) != null)
{
if (s.Contains("ADD GTRX:"))
{
try
{
}
}
}
}
UPDATE
Everything working fine except one more condition i have to satisfy.Here for for ADD Gtrx: i am taking all values including Freq when ISMAINBCCH=YES ,but at the same time ISMAINBCCH=NO there are values for Freq which i have to get as comma seperated values.For example Like here First i will take FREQ where CELLID = 639(dynamic one anything can happen) and ISMAINBCCH=YES,that i have done now next task is i have to contenate FREQ values in a comma seperated way where CELLID=639 and ISMAINBCCH=NO, so here the output i want is 24,28,67 .How to achieve this one
lines are
ADD GTRX:TRXID=0, TRXNAME="M_RAK_JeerExch_G_1879_18791_A-0", FREQ=81, TRXNO=0, CELLID=639, IDTYPE=BYID, ISMAINBCCH=YES, ISTMPTRX=NO, GTRXGROUPID=2556;
ADD GTRX:TRXID=1, TRXNAME="M_RAK_JeerExch_G_1879_18791_A-1", FREQ=24, TRXNO=1, CELLID=639, IDTYPE=BYID, ISMAINBCCH=NO, ISTMPTRX=NO, GTRXGROUPID=2556;
ADD GTRX:TRXID=5, TRXNAME="M_RAK_JeerExch_G_1879_18791_A-2", FREQ=28, TRXNO=2, CELLID=639, IDTYPE=BYID, ISMAINBCCH=NO, ISTMPTRX=NO, GTRXGROUPID=2556;
ADD GTRX:TRXID=6, TRXNAME="M_RAK_JeerExch_G_1879_18791_A-3", FREQ=67, TRXNO=3, CELLID=639, IDTYPE=BYID, ISMAINBCCH=NO, ISTMPTRX=NO, GTRXGROUPID=2556;
UPDATE
Finally i did it like shown below code
i created one more property DEFINED_TCH_FRQ = null for getting concatenated string.But the problem is it is very slow .I am iterating text file two times ,first time is sr.readline() and second is for getting concatenated string by File.Readline(this aslo previously i used File.Readalllines and got out of memory exception)
List<int> intarr = new List<int>();
intarr.Clear();
var gtrx = new Gtrx
{
CellId = int.Parse(PullValue(s, "CELLID")),
Freq = int.Parse(PullValue(s, "FREQ")),
TrxNo = int.Parse(PullValue(s, "TRXNO")),
IsMainBcch = PullValue(s, "ISMAINBCCH").ToUpper() == "YES",
Commabcch = new List<string> { PullValue(s, "ISMAINBCCH") },
DEFINED_TCH_FRQ = null,
TrxName = PullValue(s, "TRXNAME"),
};
if (!intarr.Contains(gtrx.CellId))
{
if (!_dictionary.ContainsKey(gtrx.CellId))
{
// No GCell record for this id. Do something!
continue;
}
intarr.Add(gtrx.CellId);
string results = string.Empty;
var result = String.Join(",",
from ss in File.ReadLines(filename)
where ss.Contains("ADD GTRX:")
where int.Parse(PullValue(ss, "CELLID")) == gtrx.CellId
where PullValue(ss, "ISMAINBCCH").ToUpper() != "YES"
select int.Parse(PullValue(ss, "FREQ")));
results = result;
var gtrxnew = new Gtrx
{
DEFINED_TCH_FRQ = results
};
_dictionary[gtrx.CellId].Gtrx = gtrx;
UPDATE
Finally i did it like first i saved lines starting with ADD GTRX in to an array by using File.Readalllines and then used only that array to get concatenated string instead of storing entire text file and got some performance improvement.Now my question is if i convert my Text files each contain hundreds of thousands of lines in to xml and then retrieve data from xml file, will it make any performance improvement? if i use datatable and dataset rather than classes here will it make any performance improvement?

Assuming the data is consistent and I'm also assuming the GCells will come before GTrx line (since GTrx is referencing the id of the GCell), then you could create a simple parser for doing this and store the values in a dictionary.
First thing to do is create a class to hold the Gtrx data and the GCell data. Keep in mind that I am just grabbing a subset of the data. You can add to this if you need more fields:
private class Gtrx
{
public int Freq { get; set; }
public int TrxNo { get; set; }
public string TrxName { get; set; }
public int CellId { get; set; }
public bool IsMainBcch { get; set; }
}
private class Gcell
{
public int CellId { get; set; }
public string CellName { get; set; }
public string Mcc { get; set; }
public int Lac { get; set; }
public int Ci { get; set; }
}
In addition to these classes, we will also need a class to "link" these two classes together:
private class GcellGtrx
{
public Gcell Gcell { get; set; }
public Gtrx Gtrx { get; set; }
}
Now we can build a simple parser:
private readonly Dictionary<int, GcellGtrx> _dictionary = new Dictionary<int, GcellGtrx>();
string data = "ADD GCELL:CELLID=13, CELLNAME=\"NR_0702_07021_G1_A\", MCC=\"424\", MNC=\"02\", LAC=6112, CI=7021, NCC=6, BCC=0, EXTTP=Normal_cell, IUOTP=Concentric_cell, ENIUO=ON, DBFREQBCCHIUO=Extra, FLEXMAIO=OFF, CSVSP=3, CSDSP=5, PSHPSP=4, PSLPSVP=6, BSPBCCHBLKS=1, BSPAGBLKSRES=4, BSPRACHBLKS=1, TYPE=GSM900_DCS1800, OPNAME=\"Tester\", VIPCELL=NO" + Environment.NewLine;
data = data + "ADD GTRX:TRXID=11140, TRXNAME=\"T_RAK_JaziratHamra_G_702_7021_A-0\", FREQ=99, TRXNO=0, CELLID=13, IDTYPE=BYID, ISMAINBCCH=YES, ISTMPTRX=NO, GTRXGROUPID=80;" + Environment.NewLine;
using (var sr = new StringReader(data))
{
string line = sr.ReadLine();
while (line != null)
{
line = line.Trim();
if (line.StartsWith("ADD GCELL:"))
{
var gcell = new Gcell
{
CellId = int.Parse(PullValue(line, "CELLID")),
CellName = PullValue(line, "CELLNAME"),
Ci = int.Parse(PullValue(line, "CI")),
Lac = int.Parse(PullValue(line, "LAC")),
Mcc = PullValue(line, "MCC")
};
var gcellGtrx = new GcellGtrx();
gcellGtrx.Gcell = gcell;
_dictionary.Add(gcell.CellId, gcellGtrx);
}
if (line.StartsWith("ADD GTRX:"))
{
var gtrx = new Gtrx
{
CellId = int.Parse(PullValue(line, "CELLID")),
Freq = int.Parse(PullValue(line, "FREQ")),
TrxNo = int.Parse(PullValue(line, "TRXNO")),
IsMainBcch = PullValue(line, "ISMAINBCCH").ToUpper() == "YES",
TrxName = PullValue(line, "TRXNAME")
};
if (!_dictionary.ContainsKey(gtrx.CellId))
{
// No GCell record for this id. Do something!
continue;
}
_dictionary[gtrx.CellId].Gtrx = gtrx;
}
line = sr.ReadLine();
}
}
// Now you can pull your data using a CellId:
// GcellGtrx cell13 = _dictionary[13];
//
// Or you could iterate through each one:
// foreach (KeyValuePair<int, GcellGtrx> kvp in _dictionary)
// {
// int key = kvp.Key;
// GcellGtrx gCellGtrxdata = kvp.Value;
// // Do Stuff
// }
And finally, we need to define a simple helper method:
private string PullValue(string line, string key)
{
key = key + "=";
int ndx = line.IndexOf(key, 0, StringComparison.InvariantCultureIgnoreCase);
if (ndx >= 0)
{
int ndx2 = line.IndexOf(",", ndx, StringComparison.InvariantCultureIgnoreCase);
if (ndx2 == -1)
ndx2 = line.Length - 1;
return line.Substring(ndx + key.Length, ndx2 - ndx - key.Length).Trim('"').Trim();
}
return "";
}
That should do it! See if that doesn't work for you. Keep in mind that this is very basic. You'd probably want to handle some possible errors (such as the key not existing, etc).

You didn't specify what exactly is going wrong, but my guess is that the problem you are having is caused by your split:
string[] str1 = str.Split('=');
This split causes your strings to be " CELLID" and "13" (from your file example). Notice the space in front of "CELLID". This causes the following code to never pass:
if (str1[0] == "CELLID")
You could change it to:
if (str1[0].Trim() == "CELLID")
it might work.

Related

Grouping records together using multiple record types in CsvHelper

I have a large log file containing different record types that I want to parse. It looks something like this:
$L,8,PO
$L,8,SF
$P,8,P,0,102,0,19:08:34.463
$P,9,P,0,110,0,19:08:34.460
$P,8,P,0,105,0,19:08:34.407
$L,8,SF
$P,9,A,0,139,0,19:08:34.374
$P,15,P,0,103,0,19:08:34.532
$P,8,P,0,73,0,19:08:34.436
$L,8,SF
$L,8,PI
I'm currently using CsvHelper and followed this example of how to read multiple record types using a switch statement. I'm a bit stuck however, as I want to group the $P records depending on values contained in the $L records and then write the output to separate CSV files.
For example, the first and last $L records both contain an 8 in the second field, plus PO/PI messages (this would be the start/end of my file for all $P records containing 8 in the second field). The file output for 8.csv would look like this:
$P,8,P,0,102,0,19:08:34.463
$P,8,P,0,105,0,19:08:34.407
$P,8,P,0,73,0,19:08:34.436
In addition to grouping them together this way, I would like to prepend a number ahead of the $P record depending on the $L messages which contain SF and the number 8. There are 3 SF messages above containing SF and 8, so the final file would look something like this:
1,$P,8,P,0,102,0,19:08:34.463
1,$P,8,P,0,105,0,19:08:34.407
2,$P,8,P,0,73,0,19:08:34.436
What's the best way to accomplish this? Currently I'm adding all $P messages that contain the same ID number to a dictionary with key value pair of : List<$P Record>, and I'm not quite sure how to make the $P record groupings depend on the values of the other record.
Try something like this. It is easier to add lines to a record and then group the records.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace ConsoleApplication184
{
class Program
{
const string FILENAME = #"c:\temp\test.txt";
static void Main(string[] args)
{
int count = 0;
string line = "";
StreamReader reader = new StreamReader(FILENAME);
List<Record> records = new List<Record>();
while ((line = reader.ReadLine()) != null)
{
int startComment = line.IndexOf("//");
if (startComment >= 0)
{
line = line.Substring(0, startComment);
}
line = line.Trim();
string[] splitArray = line.Split(new char[] { ',' }).ToArray();
Record newRecord = new Record();
newRecord.car = int.Parse(splitArray[1]);
newRecord.type = (Record.RECORD_TYPE)Enum.Parse(typeof(Record.RECORD_TYPE), splitArray[2]);
records.Add(newRecord);
switch (splitArray[0])
{
case "$P":
newRecord.message = line;
break;
}
}
var cars = records.GroupBy(x => x.car);
foreach (var car in cars)
{
int lap = 0;
int stint = 0;
foreach (Record record in car)
{
record.lap = lap;
record.stint = stint;
switch (record.type)
{
case Record.RECORD_TYPE.SF:
record.lap = ++lap;
break;
case Record.RECORD_TYPE.P:
string output = string.Join(",", new string[] { record.stint.ToString(), record.lap.ToString(), record.message });
Console.WriteLine(output);
break;
case Record.RECORD_TYPE.PO :
record.stint = ++stint;
break;
}
}
}
Console.ReadLine();
}
}
public class Record
{
public enum RECORD_TYPE
{
PO,
SF,
P,
PI,
A
}
public RECORD_TYPE type { get; set; }
public int stint { get; set; }
public int lap { get; set; }
public int car { get; set; }
public string message { get; set; }
}
}

C# examining and replacing tuple values based on other tuple

I'm starting with programming and C# and I have two tuples. One tuple is representing a list of points:
static List<(string, string, string)> PR { get; set; } = new List<(string, string, string)>()
{
("P1", "0", "0"),
("P2", "P1", "P1+Height"),
("P3", "P1+Width", "P2"),
("P4", "P3", "P3+Height")
};
where Item1 in the list of tuples stands for a Point name (P1, P2, P3, P4) and Item2 and Item3 represent a parametric formula for respectively the x- and y-value of a point.
"P1" in the second item in the above list should look for the tuple starting with "P1", and then for the second item in that tuple, in this case, 0.
I have a second list of tuples that represent the parameters that I need to calculate the above point values.
static List<(string, double)> PAR { get; set; } = new List<(string, double)>()
{
("Height", 500),
("Width", 1000)
};
Say I want to calculate the value of the parametric formula "P3+Height" as follows:
P3+Height --> P2 (+Height) --> P1+Height (+Height) --> 0 (+Height (+Height) --> 0 + Height + Height;
In the end I want to replace the parameter strings with the actual values (0 + 500 + 500 -> P3+Height = 1000) but thats of later concern.
Question: I'm trying to make a function that recursively evaluates the list of tuples and keeps the parameter names, but also looks for the corresponding tuple until we reach an end or exit situation. This is where I'm at now but I have a hard time getting my thought process in actual working code:
static void Main(string[] args)
{
//inputString = "P3+Height"
string inputString = PR[3].Item3;
string[] returnedString = GetParameterString(inputString);
#region READLINE
Console.ReadLine();
#endregion
}
private static string[] GetParameterString(string inputString)
{
string[] stringToEvaluate = SplitInputString(inputString);
for (int i = 0; i < stringToEvaluate.Length; i++)
{
//--EXIT CONDITION
if (stringToEvaluate[0] == "P1")
{
stringToEvaluate[i] = "0";
}
else
{
if (i % 2 == 0)
{
//Check if parameters[i] is point string
var value = PAR.Find(p => p.Item1.Equals(stringToEvaluate[i]));
//Check if parameters[i] is double string
if (double.TryParse(stringToEvaluate[i], out double result))
{
stringToEvaluate[i] = result.ToString();
}
else if (value == default)
{
//We have a point identifier
var relatingPR = PR.Find(val => val.Item1.Equals(stringToEvaluate[i])).Item2;
//stringToEvaluate[i] = PR.Find(val => val.Item1.Equals(pointId)).Item2;
stringToEvaluate = SearchParameterString(relatingPR);
}
else
{
//We have a parameter identifier
stringToEvaluate[i] = value.Item2.ToString();
}
}
}
}
return stringToEvaluate;
}
private static string[] SplitInputString(string inputString)
{
string[] splittedString;
splittedString = Regex.Split(inputString, Delimiters);
return splittedString;
}
Can anyone point me in the right direction of how this could be done with either recursion or some other, better, easier way?
In the end, I need to get a list of tuples like this:
("P1", "0", "0"),
("P2", "0", "500"),
("P3", "1000", "500"),
("P4", "1000", "1000")
Thanks in advance!
I wrote something that does this - I changed a bit of the structure to simplify the code and runtime, but it still returns the tuple you expect:
// first I used dictionaries so we can search for the corresponding value efftiantly:
static Dictionary<string, (string width, string height)> PR { get; set; } =
new Dictionary<string, (string width, string height)>()
{
{ "P1", ("0", "0") },
{ "P2", ("P1", "P1+Height")},
{ "P3", ("P1+Width", "P2") },
{ "P4", ("P3", "P3+Height") }
};
static Dictionary<string, double> PAR { get; set; } = new Dictionary<string, double>()
{
{ "Height", 500 },
{ "Width", 1000 }
};
static void Main(string[] args)
{
// we want to "translate" each of the values height and width values
List<(string, string, string)> res = new List<(string, string, string)>();
foreach (var curr in PR)
{
// To keep the code generic we want the same code to run for height and width-
// but for functionality reasons we need to know which it is - so sent it as a parameter.
res.Add((curr.Key,
GetParameterVal(curr.Value.width, false).ToString(),
GetParameterVal(curr.Value.height, true).ToString()));
}
#region READLINE
Console.ReadLine();
#endregion
}
private static double GetParameterVal(string inputString, bool isHeight)
{
// for now the only delimiter is + - adapt this and the code when \ as needed
// this will split string with the delimiter ("+height", "-500", etc..)
string[] delimiters = new string[] { "\\+", "\\-" };
string[] stringToEvaluate =
Regex.Split(inputString, string.Format("(?=[{0}])", string.Join("", delimiters)));
// now we want to sum up each "part" of the string
var sum = stringToEvaluate.Select(x =>
{
double result;
int factor = 1;
// this will split from the delimiter, we will use it as a factor,
// ["+", "height"], ["-", "500"] etc..
string[] splitFromDelimiter=
Regex.Split(x, string.Format("(?<=[{0}])", string.Join("|", delimiters)));
if (splitFromDelimiter.Length > 1) {
factor = int.Parse(string.Format($"{splitFromDelimiter[0]}1"));
x = splitFromDelimiter[1];
}
if (PR.ContainsKey(x))
{
// if we need to continue recursively translate
result = GetParameterVal(isHeight ? PR[x].height : PR[x].width, isHeight);
}
else if (PAR.ContainsKey(x))
{
// exit condition
result = PAR[x];
}
else
{
// just in case we didnt find something - we should get here
result = 0;
}
return factor * result;
}).Sum();
return sum;
}
}
}
I didnt add any validity checks, and if a value wasn't found it recieves a val of 0, but go ahead and adapt it to your needs..
Here a a working example for your question... It took me a lot of time so I hope you appreciate it: The whole code is comented line by line. If you have any question do not hesitate to ask me !
First of all we create a class named myEntry that will represent an entry. The name has to be unique e.g P1, P2, P3
public class myEntry
{
public string Name { get; private set; } //this field should be unique
public object Height { get; set; } //Can contain a reference to another entry or a value also as many combinations of those as you want.
// They have to be separated with a +
public object Width { get; set; } //same as for height here
public myEntry(string name, object height, object width)
{
//Set values
this.Name = name;
this.Height = height;
this.Width = width;
}
}
Now I create a dummy Exception class for an exception in a further class (you will see the use of this further on. Just ignore it for now)
public class UnknownEntry : Exception
{
//Create a new Class that represents an exception
}
Now we create the important class that will handle the entries and do all the work for us. This might look complicated but if you don't want to spend time understanding it you can just copy paste it, its a working solution!
public class EntryHolder
{
private Dictionary<string, double> _par = new Dictionary<string, double>(); //Dictionary holding our known variables
private List<myEntry> _entries; //List holding our entries
public EntryHolder()
{
_entries = new List<myEntry>(); //Create list
//Populate dictionary
_par.Add("Height", 500);
_par.Add("Width", 1000);
}
public bool Add(myEntry entry)
{
var otherEntry = _entries.FirstOrDefault(x => x.Name.Equals(entry.Name)); //Get entry with same name
if(otherEntry != null)
{
//Entry with the same name as another entry
//throw new DuplicateNameException(); //Throw an exception if you want
return false; //or just return false
}
//Entry to add is valid
_entries.Add(entry); //Add entry
return true; //return success
}
public void Add(List<myEntry> entries)
{
foreach (var entry in entries) //Loop through entries
{
Add(entry);
}
}
public myEntry GetEntry(string uniqueName)
{
var entry = GetRawEntry(uniqueName); //Get raw entry
var heightToCalculate = entry.Height.ToString(); //Height to calculate to string
var widthToCalculate = entry.Width.ToString(); //Width to calculate to string
entry.Height = Calculate(heightToCalculate, true); //Calculate height
entry.Width = Calculate(widthToCalculate, false); //Calculate width
return entry; //return entry
}
public List<myEntry> CalculateAllEntries()
{
List<myEntry> toReturn = new List<myEntry>(); //Create list that we will return after the calculation finished
foreach (var entryToCalculate in _entries) //Loop through all entries
{
toReturn.Add(GetEntry(entryToCalculate.Name)); //calculate entry values and add them to the list we will return after
}
return toReturn; //return list after the whole calculation finished
}
private double Calculate(string toCalculate, bool isHeight)
{
if (!toCalculate.Contains("+"))
{
//String doesn't contain a + that means it has to be a number or a key in our dictionary
object toConvert = toCalculate; //Set the object we want to convert to double
var entryCorrespondingToThisValue = _entries.FirstOrDefault(x => x.Name.Equals(toCalculate)); //Check if the string is a reference to another entry
if (entryCorrespondingToThisValue != null)
{
//It is the name of another object
toConvert = isHeight ? entryCorrespondingToThisValue.Height : entryCorrespondingToThisValue.Width; //Set object to convert to the height or width of the object in entries
}
try
{
return Convert.ToDouble(toConvert); //try to convert and return if success
}
catch (Exception e)
{
//the given height object has the wrong format
//Format: (x + Y + z ...)
throw new FormatException();
}
}
//Contains some +
var spitedString = toCalculate.Split(new char[] {'+'}); //Split
double sum = 0d; //Whole sum
foreach (var splited in spitedString) //Loop through all elements
{
double toAdd = 0; //To add default = 0
if (_par.ContainsKey(splited)) //Check if 'splited' is a key in the dictionary
{
//part of object is in the par dictionary so we get the value of it
toAdd = _par[splited]; //get value corresponding to key in dictionary
}
else
{
//'splited' is not a key in the dictionary
object toConvert = splited; //set object to convert
var entryCorrespondingToThisValue = _entries.FirstOrDefault(x => x.Name.Equals(splited)); //Does entries contain a reference to this value
if (entryCorrespondingToThisValue != null)
{
//It is a reference
toConvert = isHeight ? entryCorrespondingToThisValue.Height : entryCorrespondingToThisValue.Width; //Set to convert to references height or width
}
try
{
toAdd = Convert.ToDouble(toConvert); //Try to convert object
}
catch (Exception e)
{
//A part of the given height is not a number or is known in the par dictionary
throw new FormatException();
}
}
sum += toAdd; //Add after one iteration
}
return sum; //return whole sum
}
public myEntry GetRawEntry(string uniqueName)
{
var rawEntry = _entries.FirstOrDefault(x => x.Name.Equals(uniqueName)); //Check for entry in entries by name (unique)
if (rawEntry == null)
{
//Entry is not in the list holding all entries
throw new UnknownEntry(); //throw an exception
return null; //Or just return null
}
return rawEntry; //return entry
}
}
And here the end, the test and prove that it works:
public void TestIt()
{
List<myEntry> entries = new List<myEntry>()
{
new myEntry("P1", 0, 0),
new myEntry("P2", "P1", "P1+Height"),
new myEntry("P3", "P1+Height", "P2"),
new myEntry("P4", "P3", "P3+Height"),
};
EntryHolder myEntryHolder = new EntryHolder();
myEntryHolder.Add(entries);
var calculatedEntries = myEntryHolder.CalculateAllEntries();
}
Here an image of how it looks like:

change string in C# [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
I am new to C# and not so expert in string manipulation. I have a string which represents the position of an object in diagram. The string contains integer values which I want to change for each object.
Example
String Position = "l=50; r=190; t=-430; b=-480";
I want to modify this string to
String Position = "l=50; r=190; t=-505; b=-555";
So if you notice t = -430 is changed to t = -505 and b = -480 to b = -555 which means an increment of -75 in both top and bottom
How can I do this ?
Thanks
If you want to easily populate or modify the values in your input string, you can use string.Format(), like this:
Position = string.Format("l={0}; r={1}; t={2}; b={3}", 50, 190, -430, -480);
You can extract the values of an existing input string using regular expressions, like this:
String Position = "l=50; r=190; t=-430; b=-480";
string pattern = #"^l=(\-{0,1}\d+); r=(\-{0,1}\d+); t=(\-{0,1}\d+); b=(\-{0,1}\d+)$";
var captGroups = Regex.Match(Position, pattern).Groups;
var l = captGroups[1];
var r = captGroups[2];
var t = captGroups[3];
var b = captGroups[4];
You need to parse your expression. Here is an example, in which the string is first splitted for ; and then each part is splitted by =:
var position = "l=50; r=190; t=-430; b=-480";
var parts = position.Split(';'); // split string into 4 parts
var assignments = new Dictionary<string, int>();
foreach (var part in parts)
{
var trimmedPart = part.Trim();
var assignmentParts = trimmedPart.Split('='); // split each part into variable and value part
var value = Int32.Parse(assignmentParts[1]); // convert string to integer value
assignments.Add(assignmentParts[0], value);
}
// change values
assignments["t"] = -505;
assignments["b"] = -555;
// build new string
var newPosition = String.Join("; ", assignments.Select(p => p.Key + "=" + p.Value));
Console.WriteLine(">> " + newPosition);
String Position = "l=50; r=190; t=-430; b=-480";
public void modifyPosition(int l, int r, int t, int b)
{
string[] parts = Position.Split(';');
int oldL = int.Parse(parts[0].Replace("l=","").Trim());
int oldR = int.Parse(parts[1].Replace("r=","").Trim());
int oldT = int.Parse(parts[2].Replace("t=","").Trim());
int oldB = int.Parse(parts[3].Replace("b=","").Trim());
Position = "l="+(oldL+l).ToString()+"; r="+(oldR+r).ToString()+
"; t="+(oldT+t).ToString()+"; b="+(oldB+b).ToString()+";";
}
There are a lot of ways to generalize and optimize that -- I'll leave those up to you...
To provide a further explanation to Jeroen van Langen's comment
You should parse the string into an object, change the values and reformat a string.
You can achieve this with a similar setup to this:
public class Position
{
public int l { get; set; }
public int r { get; set; }
public int t { get; set; }
public int b { get; set; }
public override string ToString()
{
return $"l = {l}, r = {r}, t = {t}, b = {b}";
}
}
(Change the access modifiers to suit your needs)
And work with the object (simply) as below:
public void UpdatePostion()
{
// Create new position
Position pos = new Position
{
l = 50,
r = 190,
t = -430,
b = -480
};
Console.WriteLine($"Pos before change: {pos.ToString()}");
// change top and bottom value to accommodate increment
pos.t += -75;
pos.b += -75;
// Prove that they've been updated
Console.WriteLine($"Pos after change: {pos.ToString()}");
}
You don't usually want to manipulate data in string form unless the data is actually a string. In this case, you've really got a structure which is being represented as a string, so you should turn it into a structure first.
Based on the string you provided, this turns any string of a similar form into a dictionary.
var source = "l=50; r=190; t=-505; b=-555";
var components = source.Split(';').Select(x => x.Trim());
// components is now an enumerable of strings "l=50", "r=190" etc.
var pairs = components.Select(x => x.Split('=').ToArray());
// pairs is now an enumerable of arrays of strings ["l", "50"], ["r", "190"] etc;
var dictionary = pairs.ToDictionary(x => x[0], x => x[1]);
// dictionary now contains r => 190, l => 50 etc.
Of course, you want to play with actual numbers, so you want to convert the values to integers really, so swap that last line out:
var dictionary = pairs.ToDictionary(x => x[0], x => Convert.ToInt32(x[1]));
Now you have a Dictionary which you can manipulate:
dictionary["t"] = dictionary["t"] - 75;
For example. Or you could use this as the basis of populating an object with appropriate properties and manipulate those.
struct Position {
public int L { get; set; }
public int R { get; set; }
public int T { get; set; }
public int B { get; set; }
}
Of course you might want to change it back into a string when you're done manipulating it:
var newString = string.Join("; ", dictionary.Select(x => $"{x.Key}={x.Value}"));
Although if you're planning to manipulate it a lot you should keep the parsed version around for as long as possible, as the parse/render cycle could be a performance issue if you do a lot of it.
Always store your data in appropriate types. Write new classes, write new structs, they don't have to be complicated but the more you can give names and shapes to your data the easier it is to manipulate it and to ensure that you manipulated it correctly.
This is all very simplistic of course - there's no error handling, such as if the value part isn't a valid Int32 (Convert.ToInt32 will throw an exception) or if there are duplicate keys (ToDictionary will throw an exception) etc. But hopefully it gives you some idea where to go.
It's also not the only way you could parse this kind of string, but it's fairly straightforward to follow and shouldn't be too slow, although it's not going to be very memory-efficient on a large input string.
Check this fiddle here.
public class MyObject
{
public int r {get;set;}
public int l {get;set;}
public int t {get;set;}
public int b {get;set;}
public MyObject()
{
}
public void ParseFromString(string val)
{
string[] splitVal = val.Split(';');
int intVal ;
if(!int.TryParse(splitVal[0].Replace("l=","").Trim(), out intVal))
intVal = 0;
this.l = intVal;
if(!int.TryParse(splitVal[1].Replace("r=","").Trim(), out intVal))
intVal = 0;
this.r = intVal;
if(!int.TryParse(splitVal[2].Replace("t=","").Trim(), out intVal))
intVal = 0;
this.t = intVal;
if(!int.TryParse(splitVal[3].Replace("b=","").Trim(), out intVal))
intVal = 0;
this.b = intVal;
}
public string ParseToString()
{
return "l=" + this.l + "; r=" + this.r + "; t=" + this.t + "; b=" + this.b + "";
}
}
So, building on one of the comments suggestions about parsing into an object - you could represent your Position object as follows:
public class Position
{
public int Left { get; set; }
public int Right { get; set; }
public int Top { get; set; }
public int Bottom { get; set; }
public Position(string str)
{
int[] values = str.Split(new[] { "; " }, StringSplitOptions.None)
.Select(s => Convert.ToInt32(s.Substring(s.IndexOf('=') +1))).ToArray();
Left = values[0];
Right = values[1];
Top = values[2];
Bottom = values[3];
}
public override string ToString()
{
return string.Join("; ", Left, Right, Top, Bottom);
}
}
You could then use this object to serialize/deserialize your string to and from an object as follows:
string intputString = "l=50; r=190; t=-430; b=-480";
Position p = new Position(intputString);
p.Top -= 75;
p.Bottom -= 75;
string outputString = p.ToString();`
The only thing of any real complexity is turning your string into the object values. To do this we can delimit the string into each individual value by splitting the string on "; ". Each value can then be turned into an integer by taking the substring of each element after the equals character ("l=50" becomes "50") and converting it into an integer.
I think the best approach would be to use a regex in this case:
var position = "l=50; r=190; t=-430; b=-480";
var match = Regex.Match(position, #"l=(-?\d+); r=(-?\d+); t=(-?\d+); b=(-?\d+)");
if (!match.Success)
throw new Exception("invalid data");
var l = Convert.ToInt32(match.Groups[1].Value);
var r = Convert.ToInt32(match.Groups[2].Value);
var t = Convert.ToInt32(match.Groups[3].Value);
var b = Convert.ToInt32(match.Groups[4].Value);
// modify the values as you like, for example: t -= 75; b -=75;
var newPosition = $"l={l}; r={r}; t={t}; b={b}";
I think a simple method can do the trick:
public static string ModifyPositions(string positionsInput, int displacement)
{
string input = "l=50; r=190; t=-430; b=-480";
var pattern = #"(t|b)=(-?\d+)";
var regex = new Regex(pattern);
var matches = regex.Matches(input);
foreach (Match match in matches)
{
input = input.Replace(match.Groups[2].Value, (int.Parse(match.Groups[2].Value) + displacement).ToString());
}
return input;
}
In your case displacement is -75, positionsInput is "l=50; r=190; t=-430; b=-480"
You can create a Position structure, like this:
public struct Position
{
public int Left { get; private set; }
public int Top { get; private set; }
public int Right { get; private set; }
public int Bottom { get; private set; }
public Position(int left, int top, int right, int bottom)
{
Left = left;
Top = top;
Right = right;
Bottom = bottom;
}
public Position(string positionText)
{
string pattern = #"(?=l=(?<left>[\d\-]+))|(?=t=(?<top>[\d\-]+))|(?=r=(?<right>[\d\-]+))|(?=b=(?<bottom>[\d\-]+))";
Match match = Regex.Match(positionText, pattern);
int left = Convert.ToInt32(match.Groups["left"].Value);
int top = Convert.ToInt32(match.Groups["top"].Value);
int right = Convert.ToInt32(match.Groups["right"].Value);
int bottom = Convert.ToInt32(match.Groups["bottom"].Value);
Left = left;
Top = top;
Right = right;
Bottom = bottom;
}
public Position Move(int leftDelta = 0, int topDelta=0, int rightDelta=0, int bottomDelta = 0)
{
return new Position(Left + leftDelta, Top + topDelta, Right + rightDelta, Bottom + bottomDelta);
}
public override string ToString()
{
return string.Format("l={0}; r={1}; t={2}; b={3}", Left, Right, Top, Bottom);
}
}
Then you can use it like this:
Position oldPosition = new Position("l=50; r=190; t=-430; b=-480");
Position newPosition = oldPosition.Move(topDelta: -75, bottomDelta: -75);
string newPositionText = newPosition.ToString();

Sending a list of doubles as strings to the database

Just quite confused with the piece of code below.
I have class like below
public class Counter
{
public Double NormalCounter { get; set; }
public Double SATCounter { get; set; }
public Double SUNCounter { get; set; }
}
in my main class i have method to do some calculation to fill the counter
Counter CountHrs = GetBookedHours(resourceBkg, PrevEvent);
var lstExpResult = new List<string> {CountHrs.NormalCounter.ToString(),
CountHrs.SATCounter.ToString(),
CountHrs.SUNCounter.ToString()};
UpdateBooking(bookingSesid, lstExpResult);
Just assume i have the value like below in the counter
NormalCounter =4
SATCounter=10
SUNCounter=6
am trying to add in to string list and update the database.is that the right way to do ? or any other options i have please.
my update booking method is below to give clear idea.
public static bool UpdateBooking(string BookingSesid,List<string>HoursByRate)
{
SchedwinEntities db = new SchedwinEntities();
string value = string.Empty;
for (int i = 0; i < 5; i++)
{
string str = " ";
if (i < HoursByRate.Count())
{
str = HoursByRate[i];
value += str + ((char)13).ToString() + ((char)10).ToString();
}
}
var query =
from SEVTs in db.SEVTs
where
SEVTs.SESID.Trim() == BookingSesid//SESID
select SEVTs;
foreach (var SEVTs in query)
{
SEVTs.USER3 = value;//value
}
try
{
db.SaveChanges();
return true;
}
catch (UpdateException ex)
{
return false;
}
}
Rather than passing a list of strings that represent doubles, you should pass a list of key-value pairs, construct a parametersized statement from them, and use the list of key-value-pairs to bind parameter values, like this:
class SqlParamBinding {
string Name {get;set;}
object Value {get;set;}
}
var lstExpResult = new List<SqlParamBinding> {
new SqlParamBinding { Name = "NormalCounter", Value = CountHrs.NormalCounter}
, new SqlParamBinding { Name = "SATCounter", Value = CountHrs.SATCounter}
, new SqlParamBinding { Name = "SUNCounter", Value = CountHrs.SUNCounter}
};
UpdateBooking(bookingSesid, lstExpResult);
Now that lstExpResult separates names from values, your UpdateBooking code could format the SQL expression as
WHERE NormalCounter=#NormalCounter AND SATCounter=#SATCounter AND ...
and then bind #NormalCounter, #SATCounter, and #SUNCounter to the values passed in the lstExpResult list.
If it is going to list of Counter classes then have List instead of List. Looks like you might be having bunch of Counter objects that might be getting updated or sent to the database.
Counter c = new Counter();
c. NormalCounter = 4
c.SATCounter = 10
c.SunCounter = 10
List<Counter> listCounter = new List<Counter>
listCounter.Add(c);
Code is more maintainable and readable.
If you are sending one object at a time, then no need of list at all. You can pass in the counter object to your UpdateMethod and parse it while updating the database.

C# - Find Number in String and Add a Value

I have a file that looks like this:
R.D. P.N. X Y Rot Pkg
L5 120910 64.770 98.425 180 SOP8
L4 120911 -69.850 98.425 180 SOIC12
L10 120911 -19.685 83.820 180 SOIC10
L9 120911 25.400 83.820 180 0603
L5 120910 62.484 98.425 180 SOP8
And I have two text boxes labled Xinput and Yinput. From these text boxes the user enters values into them. Once the values are entered and the user clicks "GO" then I would like to take the string from the file and add the Xinput value to the X column and the Yinput value to the Y column from the file.
WHAT I MEAN...
So if the user inputs "10.552" into the Xinput textbox and "-140.123" into the Yinput textbox, the new data would look like this:
R.D. P.N. X Y Rot Pkg
L5 120910 75.322 -41.698 180 SOP8
L4 120911 -59.298 -41.698 180 SOIC12
L10 120911 -9.133 -56.303 180 SOIC10
L9 120911 35.952 -56.303 180 0603
L5 120910 73.036 -41.698 180 SOP8
QUESTIONS:
Is this possible to do?
How would I go about doing this if it is possible?
You can read the file as structured data using ADO.Net. There are ample samples for reading text files with ado.net
Once you get it in structured format in ado dataset, you can traverse and add values. Should be fairly easy.
Here is a good article
Article Link
Try this out, I don't have your file so this is a best guess. I'm sure I didn't leave out much. I know it seems overkill, but you really have full control over each value in your data this way.
public class ComponentLocation
{
public string ReferenceDesignator { get; set; }
public string PartNumber { get; set; }
public double xValue { get; set; }
public double yValue { get; set; }
public int Rotation { get; set; }
public string Package { get; set; }
}
public IEnumerable<ComponentLocation> ParseColumns(string fileName)
{
IEnumerable<string> rawData = File.ReadLines(fileName);
var rows = rawData.Skip(1).Select(l => l.Split('\t')).Select(str => new ComponentLocation
{
ReferenceDesignator = str[0],
PartNumber = str[1],
xValue = double.Parse(str[2]),
yValue = double.Parse(str[3]),
Rotation = int.Parse(str[4]),
Package = str[5]
});
return rows.ToList();
}
public void DoWork(double x, double y, string fileName)
{
var components = ParseColumns(fileName);
//Add values
foreach (var component in components)
{
component.xValue += x;
component.yValue += y;
}
//build file
StringBuilder sbData = new StringBuilder();
//header
sbData.AppendLine("R.D.\tP.N.\tX\tY\tRot\tPkg");
//data
foreach (var component in components)
{
sbData.Append(component.ReferenceDesignator).Append('\t');
sbData.Append(component.PartNumber).Append('\t');
sbData.AppendFormat("{0:###.###}", component.xValue).Append('\t');
sbData.AppendFormat("{0:###.###}", component.yValue).Append('\t');
sbData.Append(component.Rotation).Append('\t');
sbData.Append(component.Package).Append('\t').AppendLine();
}
//write
File.WriteAllText(fileName, sbData.ToString());
}
//call DoWork
DoWork(10.552, -140.123, #"C:\myfile.txt")
As first step introduce class for single entry, smth obvious like
class Entry
{
public string Rd { get; private set; }
public string Pn { get; private set; }
public double X { get; set; }
// ... declare other properties
// Initializes a new instance of the Entry class
public Entry(string rawData)
{
if (rawData == null)
{
throw new ArgumentNullException("rawData", "Nullable data structure can not be processed");
}
string[] values = rawData.Split('\t');
if (values == null || values.Count() != 6)
{
throw new ArgumentException("rawData", "Invalid data structure can not be processed");
}
this.Rd = values[0];
Double.TryParse(values[2], out this.X);
// ....
}
}
After you have build this structure you can easily add any value to X, Y...
To read a File line by line:
From MSDN
int counter = 0;
string line;
// Read the file and display it line by line.
System.IO.StreamReader file =
new System.IO.StreamReader("c:\\test.txt");
while((line = file.ReadLine()) != null)
{
Console.WriteLine (line);
counter++;
}
file.Close();
// Suspend the screen.
Console.ReadLine();
Read the entire file contents into a StringBuilder and try regular expression.

Categories

Resources