convert number index of string array to double array - c#

I am reading from a text file, pulling each line, looking for the first line with 1|, and then converting it into an array. For this I only want the 4th index so that I can sum and count the array.
Here is what is converts from the text file into an array
1|123456|01/06/2019|123456|100.00|USD|DUE UPON RECEIPT|TEST1||98790125|TEST2|TEST3|N
so [0] = 1, [2] = 123456, etc. etc. I am trying to pull 100.00 from it and put it in it's own array, so that I can easily double sum, and count the elements. It's proving difficult for me since the original array is a string though.
I've tried creating a separate string array already split, and then pulling the 4th index and creating an double array that I can count and sum. I've also tried just splitting and creating an int array in one line from the str it pulls.
string str;
using (StreamReader file = new StreamReader("c:\\testdoc.txt"))
while ((str = file.ReadLine()) != null)
{
string[] strArray = str.Split('|');
if (strArray[0] == "1")
{
double[] itotals = strArray.Select(i => Convert.ToDouble(i)).ToArray();
int count = itotals.Length;
double amt = itotals.Sum();
Console.WriteLine("Count: " + count + " Amt: " + amt);
}
else
{
}
}
I expect it to find the line starting with 1|, then tell console to write count: 1 amt: 100.00, but I actually just get errors that input strings were not in the correct format. I know that I need to pull the 4th index after I split, but I'm not sure where to do that.

Try this
string str;
int count = 0;
double amt = 0;
using (StreamReader file = new StreamReader("c:\\testdoc.txt"))
while ((str = file.ReadLine()) != null)
{
string[] strArray = str.Split('|');
if (strArray[0] == "1")
{
string itotals = strArray[4];
count = count+1;
amt = amt + Convert.ToDouble(strArray[4]);
Console.WriteLine("Count: " + count + " Amt: " + amt);
}
else
{
}
}

Related

C# - Foreach two line in Text File

I am developing in C#.
I have a text file containing the following:
Sam
NYC
Mii
Peru
LEO
Argentina
I want to iterate through this file two line by two line, then print to the console the first line, second line (the Name and the Country) of each couple, so the output would be:
Sam, NYC
Mii, Peru
Here is what I have tried:
int linenum = 0;
foreach (string line in File.ReadLines("c:\\file.txt"))
{
string word = line;
string s = "";
string j = "";
linenum = linenum + 1;
if(linenum % 2 != 0) //impaire
{
s = line;
}
else
{
j = line;
}
Console.WriteLine((string.Concat(s, j));
}
But that's not working, I want to do:
int linenum = 0;
foreach( two lines in File.ReadLines("c:\\file.txt"))
{
linenum = linenum + 1;
//get the first line (linenum = 1) and store it in a string s
// then get the second line (linenum = 2) and store it in a string j
// then print the two strings together to the console like that
Console.WriteLine((string.Concat("S: " + s,"J: " j));
}
How can I do that ?
Use File.ReadAllLines to return an array of strings:
var lines = File.ReadAllLines(filePath);
for (int i = 0; i < lines.Length; i+=2)
{
var s = lines[i];
var j = lines[i+1];
Console.WriteLine($"S: {s} J: {s}");
}
You do your output with Console.WriteLine in every line, but you also should do that only for every second line. Furthermore, your variables s and j live inside the loop's scope, so they are recreated with every iteration and loose their prior value.
int i = 0; string prev = "";
foreach (string line in File.ReadLines("c:\\file.txt")) {
if (i++ % 2 == 0) prev = line;
else Console.WriteLine($"{prev}, {line}");
}
Another approach would be iterating the array you get from File.ReadAllLines with an for loop instead of foreach and increase the index by 2
var lines = File.ReadAllLines("c:\\file.txt");
//make sure, you have an even number of lines!
if (lines.Length% 2 == 0) for (int i = 0; i < lines.Length; i+=2) {
Console.WriteLine($"{lines[i]}, {lines[i+1]}");
}
You can write yourself a little helper method to return batches of lines.
This implementation handles files that are not a multiple of the batch size (2 in your case) by returning "" for the missing lines at the end of the file.
public static IEnumerable<string[]> BatchedLinesFromFile(string filename, int batchSize)
{
string[] result = Enumerable.Repeat("", batchSize).ToArray();
int count = 0;
foreach (var line in File.ReadLines(filename))
{
result[count++] = line;
if (count != batchSize)
continue;
yield return result;
count = 0;
result = Enumerable.Repeat("", batchSize).ToArray();
}
if (count > 0)
yield return result;
}
Note that this also returns a separate array for each result, in case you make a copy of it.
Given that code, you can use it like so:
foreach (var batch in BatchedLinesFromFile(filename, 2))
{
Console.WriteLine(string.Join(", ", batch));
}
Actually, you can use LINQ to get two lines in a time using Take
var twoLines = File.ReadLines(#"YourPath").Take(2));
As you can use Skip to skip the two lines you took and take the next two lines like :
var twoLines = File.ReadLines(#"YourPath").Skip(2).Take(2));
EDIT : Thanks for #derpirscher there were a performance issue so changed the code to the following :
first read the whole file and store it in a string array
then loop through it using LINQ to take two elements from the array in a time.
string[] myStringArray = File.ReadAllLines(#"YourFile.txt");
for (int i = 0; i < myStringArray.Length ; i+=2)
{
var twoLines = myStringArray.Skip(i).Take(2).ToArray();
}
Another one, using Enumerable.Repeat() and an interger selector incremented a [NumberOfLines / 2] times.
Could be interesting for the LINQ addicted (a for / foreach solution is probably better anyway).
string[] input = File.ReadAllLines([SourcePath]);
int Selector = -1;
string[] output = Enumerable.Repeat(0, input.Length / 2).Select(_ => {
Selector += 2;
return $"{input[Selector - 1]} {input[Selector]}";
}).ToArray();
The output is:
Sam NYC
Mii Peru
LEO Argentina
Use the right tool for the job. foreach() is not the right tool here.
Without giving up the memory efficiency of ReadLines() over ReadAll():
using (var lines = File.ReadLines("c:\\file.txt").GetEnumerator())
{
while (lines.MoveNext())
{
string firstLine = lines.Current;
if (!lines.MoveNext())
throw new InvalidOperationException("odd nr of lines");
string secondLine = lines.Current;
// use 2 lines
Console.WriteLine("S: " + firstLine ,"J: " + secondLine);
}
}

How to parse below string in C#?

Please someone to help me to parse these sample string below? I'm having difficulty to split the data and also the data need to add carriage return at the end of every event
sample string:
L,030216,182748,00,FF,I,00,030216,182749,00,FF,I,00,030216,182750,00,FF,I,00
batch of events
expected output:
L,030216,182748,00,FF,I,00 - 1st Event
L,030216,182749,00,FF,I,00 - 2nd Event
L,030216,182750,00,FF,I,00 - 3rd Event
Seems like an easy problem. Something as easy as this should do it:
string line = "L,030216,182748,00,FF,I,00,030216,182749,00,FF,I,00,030216,182750,00,FF,I,00";
string[] array = line.Split(',');
StringBuilder sb = new StringBuilder();
for(int i=0; i<array.Length-1;i+=6)
{
sb.AppendLine(string.Format("{0},{1} - {2} event",array[0],string.Join(",",array.Skip(i+1).Take(6)), "number"));
}
output (sb.ToString()):
L,030216,182748,00,FF,I,00 - number event
L,030216,182749,00,FF,I,00 - number event
L,030216,182750,00,FF,I,00 - number event
All you have to do is work on the function that increments the ordinals (1st, 2nd, etc), but that's easy to get.
This should do the trick, given there are no more L's inside your string, and the comma place is always the sixth starting from the beginning of the batch number.
class Program
{
static void Main(string[] args)
{
String batchOfevents = "L,030216,182748,00,FF,I,00,030216,182749,00,FF,I,00,030216,182750,00,FF,I,00,030216,182751,00,FF,I,00,030216,182752,00,FF,I,00,030216,182753,00,FF,I,00";
// take out the "L," to start processing by finding the index of the correct comma to slice.
batchOfevents = batchOfevents.Substring(2);
String output = "";
int index = 0;
int counter = 0;
while (GetNthIndex(batchOfevents, ',', 6) != -1)
{
counter++;
if (counter == 1){
index = GetNthIndex(batchOfevents, ',', 6);
output += "L, " + batchOfevents.Substring(0, index) + " - 1st event\n";
batchOfevents = batchOfevents.Substring(index + 1);
} else if (counter == 2) {
index = GetNthIndex(batchOfevents, ',', 6);
output += "L, " + batchOfevents.Substring(0, index) + " - 2nd event\n";
batchOfevents = batchOfevents.Substring(index + 1);
}
else if (counter == 3)
{
index = GetNthIndex(batchOfevents, ',', 6);
output += "L, " + batchOfevents.Substring(0, index) + " - 3rd event\n";
batchOfevents = batchOfevents.Substring(index + 1);
} else {
index = GetNthIndex(batchOfevents, ',', 6);
output += "L, " + batchOfevents.Substring(0, index) + " - " + counter + "th event\n";
batchOfevents = batchOfevents.Substring(index + 1);
}
}
output += "L, " + batchOfevents + " - " + (counter+1) + "th event\n";
Console.WriteLine(output);
}
public static int GetNthIndex(string s, char t, int n)
{
int count = 0;
for (int i = 0; i < s.Length; i++)
{
if (s[i] == t)
{
count++;
if (count == n)
{
return i;
}
}
}
return -1;
}
}
Now the output will be in the format you asked for, and the original string has been decomposed.
NOTE: the getNthIndex method was taken from this old post.
If you want to split the string into multiple strings, you need a set of rules,
which are implementable. In your case i would start splitting the complete
string by the given comma , and than go though the elements in a loop.
All the strings in the loop will be appended in a StringBuilder. If your ruleset
say you need a new line, just add it via yourBuilder.Append('\r\n') or use AppendLine.
EDIT
Using this method, you can also easily add new chars like L or at the end rd Event
Look for the start index of 00,FF,I,00 in the entire string.
Extract a sub string starting at 0 and index plus 10 which is the length of the characters in 1.
Loop through it again each time with a new start index where you left of in 2.
Add a new line character each time.
Have a try the following:
string stream = "L,030216,182748,00,FF,I,00, 030216,182749,00,FF,I,00, 030216,182750,00,FF,I,00";
string[] lines = SplitLines(stream, "L", "I", ",");
Here the SplitLines function is implemented to detect variable-length events within the arbitrary-formatted stream:
string stream = "A;030216;182748 ;00;FF;AA;01; 030216;182749;AA;02";
string[] lines = SplitLines(batch, "A", "AA", ";");
Split-rules are:
- all elements of input stream are separated by separator(, for example).
- each event is bounded by the special markers(L and I for example)
- end marker is previous element of event-sequence
static string[] SplitLines(string stream, string startSeq, string endLine, string separator) {
string[] elements = stream.Split(new string[] { separator }, StringSplitOptions.RemoveEmptyEntries);
int pos = 0;
List<string> line = new List<string>();
List<string> lines = new List<string>();
State state = State.SeqStart;
while(pos < elements.Length) {
string current = elements[pos].Trim();
switch(state) {
case State.SeqStart:
if(current == startSeq)
state = State.LineStart;
continue;
case State.LineStart:
if(++pos < elements.Length) {
line.Add(startSeq);
state = State.Line;
}
continue;
case State.Line:
if(current == endLine)
state = State.LineEnd;
else
line.Add(current);
pos++;
continue;
case State.LineEnd:
line.Add(endLine);
line.Add(current);
lines.Add(string.Join(separator, line));
line.Clear();
state = State.LineStart;
continue;
}
}
return lines.ToArray();
}
enum State { SeqStart, LineStart, Line, LineEnd };
f you want to split the string into multiple strings, you need a set of rules, which are implementable. In your case i would start splitting the complete string by the given comma , and than go though the elements in a loop. All the strings in the loop will be appended in a StringBuilder. If your ruleset say you need a new line, just add it via yourBuilder.Append('\r\n') or use AppendLine.

how to fix error with Substring and IndexOf c#

i dont know how to fix this runtime error:
http://postimg.org/image/hh9vl7hi9/
The value of roomsInfo is : "#114|mag|nir|1||dan|nir|1||\0"
and it crash when the value is : "dan|nir|1||\0"
(in the second time of the while) when i try to do this line:
roomsInfo = roomsInfo.Substring(roomsInfo.IndexOf('|') + 1, roomsInfo.IndexOf('\0'));
this is the full code:
String roomsInfo = Program.sendToServ("#10||");
String[] room_name = new String[100];
String[] admin_name = new String[100];
String[] number_of_people = new String[100];
int check = 0, count = 0;
if(roomsInfo.IndexOf('\0') > 5)
{
roomsInfo = roomsInfo.Substring(roomsInfo.IndexOf('|')+1, roomsInfo.IndexOf('\0'));
while (roomsInfo[roomsInfo.IndexOf('|') + 2] != '\0' && roomsInfo[roomsInfo.IndexOf('|') + 1] != '\0') // #114|roomName1|RoomAdmin1|count1||roomName2|RoomAdmin2|count2||
{
if (check == 0)
{
room_name[count] = roomsInfo.Substring(0, roomsInfo.IndexOf('|'));
check = 1;
roomsInfo = roomsInfo.Substring(roomsInfo.IndexOf('|') + 1, roomsInfo.IndexOf('\0'));
}
if (check == 1)
{
admin_name[count] = roomsInfo.Substring(0, roomsInfo.IndexOf('|'));
check = 2;
roomsInfo = roomsInfo.Substring(roomsInfo.IndexOf('|') + 1, roomsInfo.IndexOf('\0'));
}
if (check == 2)
{
number_of_people[count] = roomsInfo.Substring(0, roomsInfo.IndexOf('|'));
check = 0;
count++;
roomsInfo = roomsInfo.Substring(roomsInfo.IndexOf('|') + 2, roomsInfo.IndexOf('\0'));
}
}
}
Thank you!
Nir
In order to Substring Correctly You must Get the length of substring Just like when you get length of Vector in Math.
for example you have two points in one line. say 5 and 13. To get the length between 5 and 13 you must subtract 5 from 13. so 13 - 5 = 8
int startIndex = roomsInfo.IndexOf('|') + 1;
int endIndex = roomsInfo.IndexOf('\0');
int length = endIndex - startIndex;
roomsInfo = roomsInfo.Substring(startIndex, length); // Will Get nir|1||
If you want to get the Last char too. you must add 1 to length
roomsInfo = roomsInfo.Substring(startIndex, length + 1); // Will Get nir|1||\0
From what i see in your code. your Substrings are All wrong. so you must do this to all of them.
One line solution
roomsInfo = roomsInfo.Substring(roomsInfo.IndexOf('|') + 1, roomsInfo.IndexOf('\0') - roomsInfo.IndexOf('|') - 1);
Again if you want to get last char too you must add 1 to the length.
I'm guessing that it might be something to do with the || between records (is that a record delimiter, I assume?) and your substring indexing.
What Glenn is saying would work to split a record into fields, but in your case all of your records are chained together and (I assume delimited by || ?) then finally terminated by a null zero. Therefore you would first need to split your string into set of records, before splitting the records into fields.
struct RoomInfo
{
public String RoomName;
public String AdminName;
public String WhatIsNir;
public int NumberOfPeople;
}
var roomsInfo = new List<RoomInfo>();
String allData = "#114|mag|nir|1||#115|dan|nir|1||\0".TrimEnd('\0');
String[] delimiters = new string[] { "||" };
String[] records = allData.Split(delimiters, StringSplitOptions.RemoveEmptyEntries);
foreach (var record in records)
{
String[] fields = record.Split('|');
roomsInfo.Add(new RoomInfo
{
RoomName = fields[0],
AdminName = fields[1],
WhatIsNir = fields[2],
NumberOfPeople = int.Parse(fields[3])
});
}
Another issue might be that your data and your fields are a mismatch. I.e. where do your three fields repeat in the following string? "#114|mag|nir|1||dan|nir|1||\0". I see four fields in that string, so I added one (room name) in the above example.
Of course, to use this solution is to say that there's a commitment to your data format. If this is something you are able to change (i.e. not determined by a 3rd party), then I would change it to something a little more standard. Even a basic form of CSV would be similar, but might be better.
Your implementation is extremely complex. It can be done with few lines of code, which is easier to maintain:
string roomsInfo = Program.sendToServ("#10||");
var room_name = new List<string>();
var admin_name = new List<string>();
var number_of_people = new List<string>();
if(roomsInfo.IndexOf('\0') > 5)
{
roomsInfo = roomsInfo.Substring(roomsInfo.IndexOf('|')+1, roomsInfo.IndexOf('\0'));
var records = roomsInfo.Split(new[] {"||"}, StringSplitOptions.None);
foreach (var rec in records)
{
var fields = rec.Split(new [] {'|'}, StringSplitOptions.None);
room_name.Add(fields[0]);
admin_name.Add(fields[1]);
number_of_people.Add(fields[2]);
}
}
This can be improved, of course, in order to control exceptions.

c# regular expression getting specific string from string[CLOSE]

help i want to get the specific string from my string x="Glass 1 1000"; i want to get the string "Glass" only and save it to my string type.
int[] quanvalue = new int[2];
int x1 = 0;
string type = "";
string x="Glass 1 1000";
string[] numbers = Regex.Split(x, #"\D+");
foreach (string value in numbers)
{
if (!string.IsNullOrEmpty(value))
{
int ib = int.Parse(value);
quanvalue[x1] = ib;
MessageBox.Show(quanvalue[0].ToString() + " " + quanvalue[1].ToString());
x1++;
}
else
{
// i want to get string from here
}
string sub = x.Substring(0, 5);
You can use a substring function to fetch the first 5 characters from x.
And save it in x itself

C#: Increment only the last number of a String

I have strings that look like this:
1.23.4.34
12.4.67
127.3.2.21.3
1.1.1.9
This is supposed to be a collection of numbers, separated by '.' symbols, similar to an ip address. I need to increment only the last digit/digits.
Expected Output:
1.23.4.35
12.4.68
127.3.2.21.4
1.1.1.10
Basically, increment whatever the number that is after the last '.' symbol.
I tried this:
char last = numberString[numberString.Length - 1];
int number = Convert.ToInt32(last);
number = number + 1;
If I go with the above code, I just need to replace the characters after the last '.' symbol with the new number. How do I get this done, good folks? :)
It seems to me that one method would be to:
split the string on . to get an array of components.
turn the final component into an integer.
increment that integer.
turn it back into a string.
recombine the components with . characters.
See, for example, the following program:
using System;
namespace ConsoleApplication1 {
class Program {
static void Main(string[] args) {
String original = "1.23.4.34";
String[] components = original.Split('.');
int value = Int32.Parse(components[components.Length - 1]) + 1;
components[components.Length - 1] = value.ToString();
String newstring = String.Join(".",components);
Console.WriteLine(newstring);
}
}
}
which outputs the "next highest" value of:
1.23.4.35
You can use string.LastIndexOf().
string input = "127.3.2.21.4";
int lastIndex = input.LastIndexOf('.');
string lastNumber = input.Substring(lastIndex + 1);
string increment = (int.Parse(lastNumber) + 1).ToString();
string result = string.Concat(input.Substring(0, lastIndex + 1), increment);
You need to extract more than just the last character. What if the last character is a 9 and then you add 1 to it? Then you need to correctly add one to the preceding character as well. For example, the string 5.29 should be processed to become 5.30 and not simply 5.210 or 5.20.
So I suggest you split the string into its number sections. Parse the last section into an integer. Increment it and then create the string again. I leave it as an exercise for the poster to actually write the few lines of code. Good practice!
Something like this:
var ip = "1.23.4.34";
var last = int.Parse(ip.Split(".".ToCharArray(),
StringSplitOptions.RemoveEmptyEntries).Last());
last = last + 1;
ip = string.Format("{0}.{1}",ip.Remove(ip.LastIndexOf(".")) , last);
If you are dealing with IP, there will be some extra code in case of .034, which should be 035 instead of 35. But that logic is not that complicated.
It's simple as this, use Split() and Join() String methods
String test = "1.23.4.34"; // test string
String[] splits = test.Split('.'); // split by .
splits[splits.Length - 1] = (int.Parse(splits[splits.Length - 1])+1).ToString(); // Increment last integer (Note : Assume all are integers)
String answ = String.Join(".",splits); // Use string join to make the string from string array. uses . separator
Console.WriteLine(answ); // Answer : 1.23.4.35
Using a bit of Linq
int[] int_arr = numberString.Split('.').Select(num => Convert.ToInt32(num)).ToArray();
int_arr[int_arr.Length - 1]++;
numberString = "";
for(int i = 0; i < int_arr.Length; i++) {
if( i == int_arr.Length - 1) {
numberString += int_arr[i].ToString();
}
else {
numberString += (int_arr[i].ToString() + ".");
}
}
Note: on phone so can't test.
My Solution is:
private static string calcNextCode(string value, int index)
{
if (value is null) return "1";
if (value.Length == index + 1) return value + "1";
int lastNum;
int myIndex = value.Length - ++index;
char myValue = value[myIndex];
if (int.TryParse(myValue.ToString(), NumberStyles.Integer, null, out lastNum))
{
var aStringBuilder = new StringBuilder(value);
if (lastNum == 9)
{
lastNum = 0;
aStringBuilder.Remove(myIndex, 1);
aStringBuilder.Insert(myIndex, lastNum);
return calcNextCode(aStringBuilder.ToString(), index++);
}
else
{
lastNum++;
}
aStringBuilder.Remove(myIndex, 1);
aStringBuilder.Insert(myIndex, lastNum);
return aStringBuilder.ToString();
}
return calcNextCode(value, index++);
}

Categories

Resources