Odd System.IndexOutOfRangeException when trying to overwrite .txt file c# - c#

I want to extend a data collection in a .txt file.
I'm reading a .txt file into a string array. Then I'm making a new string array with 5 more elements.
string oldarray[] = File.ReadAllLines(targetfile); //it is correctly reading the file
string newarray[] = new string[oldarray.Count()+5];
for (int i = 0; i < oldarray.Count(); i++) { //copy old array into new bigger one
newarray[i] = oldarray[i];
}
newarray[oldarray.Count() + 1] = "Data1"; //fill new space with data
newarray[oldarray.Count() + 2] = "Data2";
newarray[oldarray.Count() + 3] = "Data3";
newarray[oldarray.Count() + 4] = "Data4";
newarray[oldarray.Count() + 5] = " "; //spacer
//now write new array into same textfile over old data
File.WriteAllLines(targetfile, newarray); //System.IndexOutOfRangeException
I also tried writing line by line to the file like so, but it did just spit out the same exception:
using (StreamWriter writer = new StreamWriter(destinationFile)) //System.IndexOutOfRangeException
{
for (int i = 0; i < newarray.Length; i++)
{
writer.WriteLine(newarray[i]);
}
}
Why does it do that, and how do I fix it?

You're off by one - the last element in olaArray is at oldarray.Count() - 1, not oldarray.Count()
for (int i = 0; i < oldarray.Count(); i++){ //copy old array into new bigger one
newarray[i] = oldarray[i];
}
newarray[oldarray.Count()] = "Data1"; //fill new space with data
newarray[oldarray.Count() + 1] = "Data2";
newarray[oldarray.Count() + 2] = "Data3";
newarray[oldarray.Count() + 3] = "Data4";
newarray[oldarray.Count() + 4] = " "; //spacer

Array indexes are zero-based so oldarray.Count() + 5 points to an element after the end of the array. The first element is left empty too.
This could be fixed by fixing the indexes to be between 0 and 4 instead of 1 and 5. A better solution though would be to load the lines as a list and append the new strings :
string lines = File.ReadLines(targetfile).ToList();
var newLines=new[] {"Data1","Data2"...};
lines(newLines);
File.WriteAllLines(targetfile, lines);
Or even
var newLines=....;
string lines = File.ReadLines(targetfile)
.Concat(newLines)
.ToList();
File.WriteAllLines(targetfile, lines);
ReadAllLines uses a List as well and returns a copy of the list as an array. ReadLines on the other hand, returns lines one at a time as an IEnumerable<string>. The file remains open as long as the IEnumerable is iterated, so we need ToList() to consume it and allow the file to close before overwriting it.

The index oldarray.Count() + 5 does not exist in your new array.
Array indexing starts from zero. If you have an array with 10 elements then the first index is 0 and the last index is 9. If you make a new array with oldarray.Count() + 5 items it'll have 15 items and the last index will be 14 (not oldArray.Count + 5 which equals 15).
Just do like this:
newarray[oldarray.Count()] = "Data1";
newarray[oldarray.Count() + 1] = "Data2";
newarray[oldarray.Count() + 2] = "Data3";
newarray[oldarray.Count() + 3] = "Data4";
newarray[oldarray.Count() + 4] = " ";

Related

How to put multiple lines in NetTelegramBot KeybrardMarkup?

I'm making a telegram bot with c#.
I want to read a number of names (not more than 20 tough thy could be less) and give them to the user as keyboardMarkup. With a one dimensional array they go all in one line and it's unreadable. I wanted to make 4 line with 5 names so i tried a 4x5 array. But i get this error
Error CS0029 Cannot implicitly convert type 'NetTelegramBotApi.Types.KeyboardButton[,]' to 'NetTelegramBotApi.Types.KeyboardButton[][]'
if (text == "/lista")
{
// Read a text file line by line.
listapz = System.IO.File.ReadAllLines("listapz.txt");
string selezione = "Seleziona il paziente:";
int i = 0;
int x = 0;
int y = 0;
var arrays = new KeyboardButton[4,5];
for (i = 0; i < listapz.Length; i++)
{
y = i / 5;
x = i - (y * 5);
arrays[y,x] = new KeyboardButton("$" + (i + 1) + " " + listapz[i]);
selezione += "\n$" + (i + 1) + " " + listapz[i] + "";
}
var keyb = new ReplyKeyboardMarkup()
{
Keyboard = arrays,
OneTimeKeyboard = true,
ResizeKeyboard = true
};
var reqAction = new SendMessage(update.Message.Chat.Id, selezione) { ReplyMarkup = keyb };
bot.MakeRequestAsync(reqAction).Wait();
Console.WriteLine(reqAction);
continue;
}
any solution?
You can create new one dimensional array for every line
Then
keyb.row(first_array) //you need get only values in python it will like keyb.row(*array)
keyb.row(second_array) //and so on
and add all keyboards in one reply_markup=keyb

String array GetLength(1) working alternative

I'm using System.IO.File.ReadAllLines to read a .txt file.
It returns a string[], but a human could also call it a 2D char array, which is exactly what I'm trying to put it into. I'm trying to find out the second dimension of this array, as abstracted as possible.
string[] textFile = System.IO.File.ReadAllLines(path);
char[,] charGrid = new char[textFile.GetLength(0), textFile.GetLength(1)];
IndexOutOfRangeException: Index was outside the bounds of the array.
I know I could loop through the array and find the length of the second dimension myself, but I'm looking for a solution that is simple, readable and abstracted.
ps: my input txt file:
#111
1-1
-00
10-
You'd need to find the Length of the longest line in the file (as this approach essentially gives you a jagged array). This can be done with the following bit of code:
int dimension = textFile.Max(line => line.Length);
You'll need to add using System.Linq; in order to useMax, which will return the value of the largest Length of all strings in the textFile array.
Then just plop dimension (or whatever you want to call it) into your char array declaration.
char[,] charGrid = new char[szTest.Length, dimension];
This solution assumes each row has the same number of char.
using System;
using System.IO;
namespace ConsoleApplication
{
class Program
{
static void Main(string[] args)
{
String path = #"input.txt";
string[] textFile = File.ReadAllLines(path);
char[,] charGrid = new char[textFile.Length, textFile[0].Length];
int i, j;
i = 0;
foreach (string line in textFile)
{
j = 0;
foreach (char c in line)
{
charGrid[i, j] = c;
j++;
}
i++;
}
Console.WriteLine(charGrid[0,0] + "" + charGrid[0, 1] + "" + charGrid[0, 2]);
Console.WriteLine(charGrid[1, 0] + "" + charGrid[1, 1] + "" + charGrid[1, 2]);
Console.WriteLine(charGrid[2, 0] + "" + charGrid[2, 1] + "" + charGrid[2, 2]);
Console.ReadLine();
}
}
}

change characters position and add space between them in c#

how would you change the position of the last two characters in a string and add space between them in c#?
for example, i have a simple string "apple" and it needs to be changed to "appe l".
I have tried several things but without any success.
thanks in advance for all the answers.
In one line:
string s = "apple";
s = $"{s.Substring(0, s.Length - 2)}{s[s.Length - 1]} {s[s.Length - 2]}";
string s = "apple";
var sb = new StringBuilder(s);
var temp = sb[sb.Length - 2];
sb[sb.Length - 2] = sb[sb.Length - 1];
sb[sb.Length - 1] = temp;
sb.Insert(s.Length - 1, " ");
s = sb.ToString();
In C# string type is immutable, which means you cannot modify a string that is already created. If you need multiple modifications done, the usual way is to use StringBuilder class
string s = "apple";
var buf = new StringBuilder(s);
var ch = buf[buf.Length - 1];
buf[buf.Length - 1] = buf[buf.Length - 2];
buf[buf.Length - 2] = ch;
buf.Insert(s.Length - 1, ' ');
You can convert your string into char Array by using string.ToCharArray() method. After this interchange last 2 characters and then add space between them, just like this:
static void Main(string[] args)
{
string fruit = "apple";
char[] charFruit = fruit.ToCharArray();
char temp = charFruit[charFruit.Length - 1]; // holds the last character of the string
charFruit[charFruit.Length - 1] = charFruit[charFruit.Length - 2]; //interchnages the last two characters
charFruit[charFruit.Length - 2] = temp;
fruit = "";
for (int i = 0; i < charFruit.Length; i++){
if (i == charFruit.Length - 2){
fruit += charFruit[i].ToString();
fruit += " ";
}
else
fruit += charFruit[i].ToString();
}
Console.WriteLine(fruit);
}

Join string to 2d array, which already contains string or null

I would like to create code, to join few text files (each one has different structure) into one with unifying build.
For now, I manage to open all files, split strings in rows by tabulator and save everything into one two dimensional lists.
Example of current data:
809187.49 226885.80 26934
809183.14 226877.21 26937a
2 5509514.58 6558911.86 0.00 80T
3 5509515.55 6558913.48 0.00 80T
4 5509516.35 6558914.56 0.00 80T
Next, I am going to reprint content from a two-dimensional list into a new array (with n rows and 2 columns) and sort all data at the same time. All double type, greater then 100000.00 I want to put into the second column with ',' separator and the rest of content of each row from the list I would like to put into the first column:
Result:
26934 809187.49,226885.80
26937a 809183.14,226877.21
2,0.00,80T 5509514.58,6558911.86
3,0.00,80T 5509515.55,6558913.48
4,0.00,80T 5509516.35,6558914.56
And here is the problem. I used code like below:
string[,] resultArray = new string[RowNo, 2]; //Create Array
for (int i = 0; i < resultList.Count; i++)
{
for (int j = 0; j < Regex.Matches(file[i], " ").Count+1; j++)
{
if (double.TryParse(resultList[i][j], out n)) // record is a double type greater then n
{
if((Double.Parse(resultList[i][j]) % 1) > 0) // record is not a int type
{
if (resultArray[i, 1] != null) // if cell in array is not null
{
resultArray[i, 1].Insert(resultArray[i, 1].Count(), "," + resultList[i][j].ToString()); // add content of List in to string in second column
}
else // if cell in array is null for now
{
resultArray[i, 1].Insert(0, "," + resultList[i][j].ToString()); // put content of List in to second column
}
}
if (resultArray[i, 0] != null) //if cell in array is not null
{
resultArray[i, 0].Insert(resultArray[i, 0].Count(), ";" + resultList[i][j].ToString()); // put content of List in to first column
}
else // if cell in array is null for now
{
resultArray[i, 0].Insert(0, "," + resultList[i][j].ToString()); // put content of List in to first column
}
}
else
{
if (resultArray[i, 0] != null) //if cell in array is not null
{
resultArray[i, 0].Insert(resultArray[i, 0].Count(), ";" + resultList[i][j].ToString()); // put content of List in to first column
}
else // if cell in array is null for now
{
resultArray[i, 0].Insert(0, "," + resultList[i][j].ToString()); // put content of List in to first column
}
}
}
}
But unfortunately, when I run code I receive bug "Object reference not set to an instance of an object"
I have make some research and try something like this:
resultArray[i, 1] += resultArray[i, 1] + "," + res_file[i][j].ToString();
instead
resultArray[i, 1].Insert(resultArray[i, 1].Count(), "," + res_file[i][j].ToString());
But it wasn't work correctly. I received some results but data in record was duplicated.
I will appreciate every help.
The problem is with all your else conditions:
You are doing
if (resultArray[i, 0] != null) //if cell in array is not null
{
resultArray[i, 0].Insert(resultArray[i, 0].Count(), ";" + resultList[i][j].ToString()); // put content of List in to first column
}
else // if cell in array is null for now
{
resultArray[i, 0].Insert(0, "," + resultList[i][j].ToString()); // put content of List in to first column
}
which basically means do if block when resultArray[i, 0] != null, but in the else block you are trying to access the Insert() method of that null object. Hence the error. All of your else blocks are like that.
I think what you want to do is an assignment in your else blocks (which you seem to have figured out)... like:
resultArray[i, 0] += "," + resultList[i][j].ToString());
The problem with duplicates may have been that you are using both += and the left hand side (LHS) expression in
resultArray[i, 1] += resultArray[i, 1] + "," + res_file[i][j].ToString();
When you do x += 1; it is same as x = x + 1;
You are doing: x += x + 1; which is same as x = x + (x + 1);

Editing a line in a text file without using pointers?

I am trying to edit a line of a text file (.Hex file) containing all Hex characters without using pointers and in a more efficient way.
It takes so long because the program I have to edit some (around 30x4 bytes or 30 float values from the address values of hex file).
Every time the program replaces one byte, it searches the complete file and replaces the values, and copy back back again the new file to another file. This process repeats 30 times, which is quite time consuming and hence not looks appropriate.
What would be the most efficient method?
public static string putbyteinhexfile(int address, char data, string total)
{
int temph, temphl, tempht;
ushort checksum = 0;
string output = null, hexa = null;
StreamReader hex;
RegistryKey reg = Registry.CurrentUser;
reg = reg.OpenSubKey("Software\\Calibratortest");
hex = new StreamReader(((string)reg.GetValue("Select Input Hex File")));
StreamReader map = new StreamReader((string)reg.GetValue("Select Linker Map File"));
while ((output = hex.ReadLine()) != null)
{
checksum = 0;
temph = Convert.ToInt16(("0x" + output.Substring(3, 4)), 16);
temphl = Convert.ToInt16(("0x" + output.Substring(1, 2)), 16);
tempht = Convert.ToInt16(("0x" + output.Substring(7, 2)), 16);
if (address >= temph &&
address < temph + temphl &&
tempht == 0)
{
output = output.Remove((address - temph) * 2 + 9, 2);
output = output.Insert((address - temph) * 2 + 9,
String.Format("{0:X2}", Convert.ToInt16(data)));
for (int i = 1; i < (output.Length - 1) / 2; i++)
checksum += (ushort)Convert.ToUInt16(output.Substring((i * 2) - 1, 2), 16);
hexa = ((~checksum + 1).ToString("x8")).ToUpper();
output = output.Remove(temphl * 2 + 9, 2);
output = output.Insert(temphl * 2 + 9,
hexa.Substring(hexa.Length - 2, 2));
break;
}
else total = total + output + '\r' + '\n';
}
hex.Close();
map.Close();
return total;
}
Assuming you don't want to massively rewrite your existing logic which does 'for each line, do this search and replace logic', I'd think the simplest change would be:
var lines = File.ReadAllLines(filePath);
foreach (change to make)
{
for (int i = 0; i < lines.Length; i++)
{
// read values from line
if (need_to_modify)
{
// whatever change logic you want here.
lines[i] = lines[i].Replace(...);
}
}
}
File.WriteAllLines(filePath, lines);
Basically, you'll still do the logic you have now, except:
You read the file once instead of N times
you get rid of streamreader / streamwriter work
you do your changes on the array of strings in memory
string fileName = "blabla.hex";
StreamReader f1 = File.OpenText(fileName);
StreamWriter f2 = File.CreateText(fileName + ".temp_");
while (!f1.EndOfStream)
{
String s = f1.ReadLine();
//change the content of the variable 's' as you wish
f2.WriteLine(s);
}
f1.Close();
f2.Close();
File.Replace(fileName + ".temp_", fileName, null);

Categories