I am trying to modify a txt file, I need to change the 45 character with a P if the line starts with 8
for (int i = 0; i < textBox.Lines.Length; i++)//Loops through each line of text in RichTextBox
{
string text = textBox.Lines[i];
if ((text.Contains("8") == true)) //Checks if the line contains 8.
{
char replace = 'P';
int startindex = textBox.GetFirstCharIndexFromLine(i);
int endindex = text.Length;
textBox.Select(startindex, endindex);//Selects the text.
richTextBox1.Text = textBox.Text.Substring(0, textBox.SelectionStart) + (0, textBox.Lines) + replace + textBox.Text.Substring(textBox.SelectionStart + 45);
}}
To accomplish your goal the code could be changed in this way
//Loops through each line of text in RichTextBox
for (int i = 0; i < textBox.Lines.Length; i++)
{
string text = textBox.Lines[i];
//Checks if the line starts with "8".
if (text.StartsWith("8"))
{
// Find the 45th position from the start of the line
int startindex = textBox.GetFirstCharIndexFromLine(i) + 45;
// Starting from the found index select 1 char
textBox.Select(startindex, 1);
// Replace the selected char with the "P"
textBox.SelectedText = "P";
}
}
The key points changed are the way to select into a textbox. The Select method requires a starting index and the number of character to select, finally, once you have a SelectedText, (a read/write property) you can simply replace the current SelectedText with your own text. Lot easier than your current (and wrong) calculation.
Related
I am developing a chess engine in C#/Unity and want to print the board on a nice format. Preferably I want to print with some Unicode pieces but they end up making the board uneven, see image below:
The same seems to go for normal numbers since each row starts slightly off one another, row 1 starts more left than the others for example.
Why does my Debug.Log/prints end up like this, and how can I print them so that each character takes up the same amount of space?
EDIT:
Here is the code I use to Debug.Log the board if that helps:
public static void PrintBitboard(ulong bitboard)
{
string zero = " 0 ";
string one = " 1 ";
string printString = "";
// Loop through all squares and print a 1 if piece and 0 if not a piece on the square
for (int row = 0; row < 8; row++)
{
// Add numbering on the left side
printString += (8 - row) + " ";
for (int col = 0; col < 8; col++)
{
int currentSquare = row * 8 + col;
printString += BitOperations.GetBit(bitboard, currentSquare) != 0 ? one : zero;
}
// Change to new row
printString += "\n";
}
// Print bottom letters
printString += "\n" + " a b c d e f g h";
// Send message to the console
Debug.Log(printString);
}
What you are looking for is not "unicode" but monospace
-> As GiacomoCatenazzi already said, the only thing responsible for that is the font you are using
As a "quick and dirty" fix / alternative you could try and simply use tabs (\t) instead of spaces like (in general for larger string based concatenations I would recommend to use a StringBuider)
public static void PrintBitboard(ulong bitboard)
{
const string zero = "0\t";
const string one = "1\t";
var stringBuilder = new StringBuilder();
// Loop through all squares and print a 1 if piece and 0 if not a piece on the square
for (int row = 0; row < 8; row++)
{
// Add numbering on the left side
stringBuilder.Append((8 - row)).Append('\t');
for (int col = 0; col < 8; col++)
{
int currentSquare = row * 8 + col;
stringBuilder.Append(BitOperations.GetBit(bitboard, currentSquare) != 0 ? one : zero);
}
// Change to new row
stringBuilder.Append('\n');
}
// Print bottom letters
stringBuilder.Append("\n \ta\tb\tc\td\te\tf\tg\th");
// Send message to the console
Debug.Log(stringBuilder.ToString());
}
See .Net Fiddle which in the Unity console would look like
(in both I had to tricks a bit since I don't know what BitOperations implementation you are using)
I wonder if there's anyway i can set a maximum number of characters for a line in a RichTextBox. I know I can set a general MaxLength for the whole Box, but not for the line itself.
I was thinking that the only solution, or at least a viable one, would be to select the line in a TextRange, count the chars and check if it's greater than the max number I manually set. Then, create a new line with:
myRichTextBox.AppendText(Environment.NewLine);
and also set the caret position to the end of the selection with something similar to that:
myRichTextBox.CaretPosition = myRichTextBox.Selection.End;
Would that be the best approach for my problem, or is there an simpler way to do that?
You could set up a keypress event, when triggered, validate the key and desired length and append the Environment.NewLine when you want.
This is a tricky one I think and his code can pretty much do the trick:
private void myRichTextBox_TextChanged(object sender, EventArgs e)
{
int maxLen = 10;
int CursorIndex = myRichTextBox.SelectionStart;
var text = myRichTextBox.Text;
int startIndex = text.Substring(0, CursorIndex).LastIndexOf("\n") + 1;
int endIndex = text.IndexOf("\n", CursorIndex, text.Length - CursorIndex);
// if (startIndex < 0) startIndex = 0;
if (endIndex < 0) endIndex = text.Length;
string line = text.Substring(startIndex, endIndex - startIndex).Trim();
if (line.Length > maxLen)
{
int insertionPoint = startIndex + maxLen;
text = text.Insert(insertionPoint, "\n");
CursorIndex += (insertionPoint < CursorIndex) ? 1 : 0;
myRichTextBox.Text = text;
myRichTextBox.SelectionStart = CursorIndex;
}
}
however I think there should be a better way to do this.
The problem I am having is that I need to be able to loop over a string, returning 5 characters after the position of the index, then starting 5 characters after.
However when there are less than 5 characters left an out of range error occurs, I thought it would just print the remaining characters of the string.
string string1 = "ghuitghtruighr";
for (int index = 0; index < string1.Length; index += 5)
{
string subString = string1.Substring(i, 5);
Console.WriteLine(subString);
}
How can I get it to print what's left of the string when whats remaining is less than 5?
You could use the LINQ .Skip(...) & .Take(...) operators like so:
for (int index = 0; index < string1.Length; index += 5)
{
string subString = new String(string1.Skip(index).Take(5).ToArray());
Console.WriteLine(subString);
}
That gives:
ghuit
ghtru
ighr
Replace line 3 of OP code with this:
string subString = string1.Substring(i, string1.Length - i < 5 ? string1.Length - i : 5);
You could Substring() from the index to the end of the string and then check whether the resulting substring contains more than 5 characters:
string string1 = "ghuitghtruighr";
for (int index = 0; index < string1.Length; index += 5)
{
string subString = string1.Substring(index);
if(subString.Length > 5)
subString = subString.Substring(0, 5);
Console.WriteLine(subString);
}
Don't do the above if you have many distinct strings of great length - strings are immutable so calling Substring() twice on every iteration results in an extra string on the heap every time - rather calculate the difference between Length and index like suggested by Xerillio
I am currently sending and splitting long lines of data to Excel. Each split prints in a new row. I want to change this from splitting at a pipe symbol in the existing data to splitting at a character length of 85, but , there are chances that at character 85 it may split a word in two. How would I tell it to split further into the data if is going to split an actual word. I know if at 85 it should also find a space after. I'm curious on what to add.
// Add Description
string DescriptionSplit = srcAddOnPanel.Controls["txtProductDescAddOn" + AddRow].Text;
string[] descriptionParts = DescriptionSplit.Split('|');
int i;
for (i = 0; i <= descriptionParts.GetUpperBound(0); i++)
{
worksheet.Rows[currentRow].Insert(); //applies the description for the default bundle row
worksheet.Rows[currentRow].Font.Bold = false;
worksheet.Cells[currentRow, "E"].Value = rowIndent + descriptionParts[i].Trim();
currentRow++;
}
You could use this approach (Warning not fully tested)
int x = 85;
int y = 0;
int currentRow = 0;
// Loop until you have at least 85 char to grab
while (x + y < DescriptionSplit.Length)
{
// Find the first white space after the 85th char
while (x + y < DescriptionSplit.Length &&
!char.IsWhiteSpace(DescriptionSplit[x+y]))
x++;
// Grab the substring and pass it to Excel for the currentRow
InsertRowToExcel(DescriptionSplit.Substring(y, x), currentRow);
// Prepare variables for the next loop
currentRow++;
y = y + x + 1;
x = 85;
}
// Do not forget the last block
if(y < DescriptionSplit.Length)
InsertRowToExcel(DescriptionSplit.Substring(y), currentRow);
...
void InsertRowToExcel(string toInsert, int currentRow)
{
worksheet.Rows[currentRow].Insert();
worksheet.Rows[currentRow].Font.Bold = false;
worksheet.Cells[currentRow, "E"].Value = rowIndent + toInsert.Trim();
}
Here's a VBA version that seems to work. As suggested in my comment, it separates the string by spaces and then tests whether adding a word makes the length of the current line greater than the maximum (85). As is usual with these kinds of things getting the last word to populate correctly is hard.
If this works for you it should be simple enough to modify to C#. Let me know if that's not true:
Sub ParseRows()
Const ROW_LENGTH As Long = 85
Dim Text As String
Dim Words As Variant
Dim RowContent As String
Dim RowNum As Long
Dim i As Long
Text = ActiveCell.Text
Words = Split(Text, " ")
RowNum = 2
For i = LBound(Words) To UBound(Words)
If Len(RowContent & Words(i) & " ") > ROW_LENGTH Then
ActiveSheet.Range("A" & RowNum).Value = RowContent
RowNum = RowNum + 1
If i = UBound(Words) Then
RowContent = Words(i)
Else
RowContent = ""
End If
Else
RowContent = RowContent & Words(i) & " "
End If
Next i
If RowContent <> "" Then ActiveSheet.Range("A" & RowNum).Value = RowContent
End Sub
How do I get line and column at cursor from a text box in my Windows 8 Metro App? There is no GetFirstCharIndexFromLine method like there was in WinForms.
Here is one way to accomplish this:
// Returns a one-based line number and column of the selection start
private static Tuple<int, int> GetPosition(TextBox text)
{
// Selection start always reports the position as though newlines are one character
string contents = text.Text.Replace(Environment.NewLine, "\n");
int i, pos = 0, line = 1;
// Loop through all the lines up to the selection start
while ((i = contents.IndexOf('\n', pos, text.SelectionStart - pos)) != -1)
{
pos = i + 1;
line++;
}
// Column is the remaining characters
int column = text.SelectionStart - pos + 1;
return Tuple.Create(line, column);
}
This will get the line and column numbers.