how to fix error with Substring and IndexOf c# - 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.

Related

Add all chars of a string to a list but merge numbers to one entry C#

You have given a string like "(32+5)*20" and you need to create a list with all chars, but need to merge the numbers to one entry like "32" and "20". How to do it?
I have already tried
string formel = "(32+5)*20";
char[] zeichen = formel.ToCharArray();
var liste = new List<string>();
for(int i = 0; i < zeichen.Length ; i++)
{
if(Char.IsNumber(zeichen[i]) && formel.Substring(i, i + 1).Any(char.IsNumber))
{
liste.Add(zeichen[i].ToString() + zeichen[i+1].ToString());
}
else
{
liste.Add(zeichen[i].ToString());
}
}
You could use regex to return the groups of numbers:
var formel = "(32+5)*20";
var pattern = "([0-9]+)";
var match = Regex.Match(formel, pattern);
and then use
match.Groups
The list as posted will still contain the same number of elements as the string did, since you added to it on every loop iteration. To "merge" into one entry, you need to not add on some iterations, but instead add that digit to the previous number.
This is easier if you check if the previous item was a number, rather than the next.
for (int i = 0; i < zeichen.Length; i++)
{
if (i > 0 && Char.IsNumber(zeichen[i]) && Char.IsNumber(zeichen[i - 1])) // if got a number, and had a number before
{
// Then dont Add to the list, instead add to the number/string
liste[list.Count - 1] += zeichen[i];
//liste.Add(zeichen[i].ToString() + zeichen[i + 1].ToString());
}
else
liste.Add(zeichen[i].ToString());
}
// "(", "32", "+", "5", ")", "*", "20"
You can do it by using Regex and LINQ
var dateText = "(32 + 5) * 20";
string splitPattern = #"[^\d]";
var result = Regex.Split(dateText, splitPattern).Where(x=>x!="");
I hope this will help you #Janic

convert number index of string array to double array

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
{
}
}

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.

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++);
}

What is the most efficient way to detect if a string contains a number of consecutive duplicate characters in C#?

For example, a user entered "I love this post!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
the consecutive duplicate exclamation mark "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" should be detected.
The following regular expression would detect repeating chars. You could up the number or limit this to specific characters to make it more robust.
int threshold = 3;
string stringToMatch = "thisstringrepeatsss";
string pattern = "(\\d)\\" + threshold + " + ";
Regex r = new Regex(pattern);
Match m = r.Match(stringToMatch);
while(m.Success)
{
Console.WriteLine("character passes threshold " + m.ToString());
m = m.NextMatch();
}
Here's and example of a function that searches for a sequence of consecutive chars of a specified length and also ignores white space characters:
public static bool HasConsecutiveChars(string source, int sequenceLength)
{
if (string.IsNullOrEmpty(source))
return false;
if (source.Length == 1)
return false;
int charCount = 1;
for (int i = 0; i < source.Length - 1; i++)
{
char c = source[i];
if (Char.IsWhiteSpace(c))
continue;
if (c == source[i+1])
{
charCount++;
if (charCount >= sequenceLength)
return true;
}
else
charCount = 1;
}
return false;
}
Edit fixed range bug :/
Can be done in O(n) easily: for each character, if the previous character is the same as the current, increment a temporary count. If it's different, reset your temporary count. At each step, update your global if needed.
For abbccc you get:
a => temp = 1, global = 1
b => temp = 1, global = 1
b => temp = 2, global = 2
c => temp = 1, global = 2
c => temp = 2, global = 2
c => temp = 3, global = 3
=> c appears three times. Extend it to get the position, then you should be able to print the "ccc" substring.
You can extend this to give you the starting position fairly easily, I'll leave that to you.
Here is a quick solution I crafted with some extra duplicates thrown in for good measure. As others pointed out in the comments, some duplicates are going to be completely legitimate, so you may want to narrow your criteria to punctuation instead of mere characters.
string input = "I loove this post!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!aa";
int index = -1;
int count =1;
List<string> dupes = new List<string>();
for (int i = 0; i < input.Length-1; i++)
{
if (input[i] == input[i + 1])
{
if (index == -1)
index = i;
count++;
}
else if (index > -1)
{
dupes.Add(input.Substring(index, count));
index = -1;
count = 1;
}
}
if (index > -1)
{
dupes.Add(input.Substring(index, count));
}
The better way i my opinion is create a array, each element in array is responsible for one character pair on string next to each other, eg first aa, bb, cc, dd. This array construct with 0 on each element.
Solve of this problem is a for on this string and update array values.
You can next analyze this array for what you want.
Example: For string: bbaaaccccdab, your result array would be { 2, 1, 3 }, because 'aa' can find 2 times, 'bb' can find one time (at start of string), 'cc' can find three times.
Why 'cc' three times? Because 'cc'cc & c'cc'c & cc'cc'.
Use LINQ! (For everything, not just this)
string test = "aabb";
return test.Where((item, index) => index > 0 && item.Equals(test.ElementAt(index)));
// returns "abb", where each of these items has the previous letter before it
OR
string test = "aabb";
return test.Where((item, index) => index > 0 && item.Equals(test.ElementAt(index))).Any();
// returns true

Categories

Resources