I've got a RichTextBox, and would like to highlight a whole word, given just its ending index. Is it possible to highlight from an ending index, backwards to the first occurance of a space?
This is what I've tried so far, but I don't know if there is any other efficient methods:
int length = richTextBox.Text.Reverse().Skip(richTextBox.Text.Length - offset)
.TakeWhile(x => x != ' ')
.Count();
richTextBox.Select(offset - length, length + 1);
richTextBox.SelectionBackColor = Color.Yellow;
That's a very inefficient way to get the length.
Try this- might be off by one somewhere, I cant test it right now:
var prevSpace = richTextBox.Text.LastIndexOf(' ', offset);
var length = prevSpace = -1 ? offset + 1 : offset - prevspace;
Related
I know it may not be a best-practice solution for my problem but I'd tried to remove the first and last specific characters of a string.
Here's a string for example: "product"". I'd like to remove only the first and last " characters so the expected result would be: product".
Here's my code that produced some unexpected results and I'd like to understand why it is working like that.
var productName = "\"product\"\""; // "product""
productName.IndexOf('\"', 0) and productName.LastIndexOf('\"', 0) would be both 0 here at this point.
if (productName.IndexOf('\"', 0) == 0) productName = productName.Remove(productName.IndexOf('\"', 0), 1);
In this condition, IndexOf returns 0 as expected so productName's value will be productName"" at this point. Then, I run the following:
if (productName.LastIndexOf('\"', 0) == 0) productName = productName.Remove(productName.LastIndexOf('\"', 0), 1);
In this condition, LastIndexOf returns -1. It acts as if my variable's length remains the same after Remove but its value is shifted to the left by 1 character. Why is that?
Let's take a look at the docs for string.LastIndexOf(char, int):
Reports the zero-based index position of the last occurrence of a specified string within this instance. The search starts at a specified character position and proceeds backward toward the beginning of the string.
...
startIndex
Int32
The search starting position. The search proceeds from startIndex toward the beginning of this instance.
You're calling:
productName.LastIndexOf('\"', 0)
So you're starting at the first character in your string (index 0), and proceeding towards the beginning looking for a " character. But you're already at the beginning! So you're not going to find anything.
Just use the overloads which don't take a startIndex: you don't need it:
string.IndexOf('"')
string.LastIndexOf('"')
Please try this
var productName = "\"product\"\"";
if (productName.IndexOf('\"', 0) == 0)
productName = productName.Remove(productName.IndexOf('\"', 0), 1);
if (productName.LastIndexOf('\"', productName.Length-1) == productName.Length - 1)
productName = productName.Remove(productName.LastIndexOf('\"', productName.Length - 1), 1);
Let's say I have a string called test,
string test = "hello my dear world"
and I want to get the last letter's index, (which is 19) .
How do I get that index, and insert it into an int/string?
This is extremely simple.
string test = "Hello World";
char theLastCharacterOfTest = test[test.Length - 1]; // 'd'
int theIndexOfTheLastCharacter = test.Length - 1; // 10
Want an explanation? Here it is!
Let's start with getting the index of the last character. Since C# uses a 0-based index system (i.e. the first index is 0), the last index is the length of the string - 1.
The last character is just the character at the last index, right? And the indexer of string returns the character at the index passed in. If we combine these two, we get test[test.Length - 1].
I don't think you are very familiar with indexers, so here's a link:
https://msdn.microsoft.com/en-us/library/6x16t2tx.aspx
I'm not sure whether you're looking for the index or position of the last character (you said the index is 19, but that's the position...the index is 18). Here's both:
string test = "hello my dear world";
// The length of the text gives the position of the last char
int position = test.Length;
// C# has a 0-based index. You need the string length -1 to get the last char's position
int index = test.Length - 1;
Here's a working example.
int index = test.Length;
char LastLetter = test[index - 1];
please search , before posting your question.
string test = "hello my dear world";
int index = test.FindIndex(x => x.StartsWith("d"));
OR
int index = test.Length - 1;
I'm making a game, and I read dialogue text from an XML file. I'm trying to make a routine to add in newlines automatically as needed, so that it fits in the text box. It just won't work right, though. Here's the code as it currently is:
SpriteFont dialogueFont = font31Adelon;
int lastSpace = 0;
string builder = "";
string newestLine = "";
float maxWidth = 921.6f;
float stringLength = 0;
for (int i = 0; i <= speech.Length - 1; i++) //each char in the string
{
if (speech[i] == ' ') //record the index of the most recent space
{
lastSpace = i;
}
builder += speech[i];
newestLine += speech[i];
stringLength = dialogueFont.MeasureString(newestLine).X;
if (stringLength > maxWidth) //longer than allowed
{
builder = builder.Remove(lastSpace); //cut off from last space
builder += Environment.NewLine;
i = lastSpace; //start back from the cutoff
newestLine = "";
}
}
speech = builder;
My test string is "This is an example of a long speech that has to be broken up into multiple lines correctly. It is several lines long and doesn't really say anything of importance because it's just example text."
This is how speech ends up looking:
http://www.iaza.com/work/120627C/iaza11394935036400.png
The first line works because it happens to be a space that brings it over the limit, I think.
i = 81 and lastSpace = 80 is where the second line ends. builder looks like this before the .Remove command:
"This is an example of a long speech that\r\nhas to be broken up into multiple lines c"
and after it is run it looks like this:
"This is an example of a long speech that\r\nhas to be broken up into multiple line"
The third line goes over the size limit at i = 123 and lastSpace = 120. It looks like this before the .Remove:
"This is an example of a long speech that\r\nhas to be broken up into multiple line\r\ncorrectly. It is several lines long and doe"
and after:
"This is an example of a long speech that\r\nhas to be broken up into multiple line\r\ncorrectly. It is several lines long an"
As you can see, it cuts off an extra character, even though character 80, that space, is where it's supposed to start removing. From what I've read .Remove, when called with a single parameter, cuts out everything including and after the given index. It's cutting out i = 79 too, though! It seems like it should be easy enough to add or subtract from lastSpace to make up for this, but I either get "index out of bounds" errors, or I cut off even more characters. I've tried doing .Remove(lastSpace, i-lastSpace), and that doesn't work either. I've tried handling "ends with a space" cases differently than others, by adding or subtracting from lastSpace. I've tried breaking things up in different ways, and none of it has worked.
I'm so tired of looking at this, any help would be appreciated.
You add Environment.NewLine to your StringBuilder, you need to consider that when you specify the index where to start removing.
Environment.NewLine's value is System dependent. It can be "\r\n", "\n" or "\r" (or, only one of the first two according to MSDN).
In your case it's "\r\n", that means for removing one space, you added two other characters.
First, you need to declare a new variable:
int additionalChars = 0;
Then, when adding a line of text, you should change your code to something like this:
builder = builder.Remove(lastSpace + additionalChars); //cut off from last space
builder += Environment.NewLine;
additionalChars += Environment.NewLine.Length - 1;
The -1 is because you already removed a space (should make this code independent of the system's definition of Environment.NewLine).
UPDATE: You should also account for words that are longer than the line limit. You should break them anyway (couldn't help but have a try):
if (stringLength > maxWidth) //longer than allowed
{
// Cut off only if there was a space to cut off at
if (lastSpace >= 0) {
builder = builder.Remove(lastSpace + additionalChars); //cut off from last space
i = lastSpace; //start back from the cutoff
}
builder += Environment.NewLine;
// If there was no space that we cut off, there is also no need to subtract it here
additionalChars += Environment.NewLine.Length - (lastSpace >= 0 ? 1 : 0);
lastSpace = -1; // Means: No space found yet
newestLine = "";
}
As an alternative approach, you could break your sentence up into an array using .split and then fill your box until there isn't space for the next work, then add the newline and start on the next line.
Can you do something like the following code. The advantage is two-fold. Firstly, it skips to the next space to measure and decide whether to add the whole word or not, rather than going letter by letter. Secondly, it only calls MeasureString once for each word in the string, rather than for every letter added to the string. It uses StringBuilder with Append when the word will fit, or AppendLine when it won't fit and a new-line needs to be added.
int lastSpace = 0;
int nextSpace = s.IndexOf(' ', lastSpace + 1);
float width = 0;
float totalWidth = 0;
float maxWidth = 200;
while (nextSpace >= 0)
{
string piece = s.Substring(lastSpace, nextSpace - lastSpace);
width = g.MeasureString(piece, this.Font).Width;
if (totalWidth + width < maxWidth)
{
sb.Append(piece);
totalWidth += width;
}
else
{
sb.AppendLine(piece);
totalWidth = 0;
}
lastSpace = nextSpace;
nextSpace = s.IndexOf(' ', lastSpace + 1);
}
MessageBox.Show(sb.ToString());
I've got a RichTextBox, and would like to highlight a whole word, given just its starting index.
I've been able to highlight a word if the starting index and length is known, however in this case I do not know the length of the word. Is it possible to highlight from a starting index to the first occurance of a space?
UPDATE:
This is what I've tried so far:
resultsRichTextBox.Select(novelOffset - 2, searchString.Length);
Unfortunately 'searchstring' is not always the length of the word being searched for, so I need a way of finding the amount of characters from novelOffset - 2 till the nearest space.
You can do something like this:
int length = this.richTextBox1.Text.Skip(startIdx)
.TakeWhile(x => char.IsLetterOrDigit(x))
.Count();
this.richTextBox1.Select(startIdx, length);
this.richTextBox1.SelectionBackColor = Color.Yellow;
Obviously you can change char.IsLetterOrDigit with x != ' ' or whatever you prefer.
You can use the String.IndexOf(Char, Int32):
Reports the zero-based index of the first occurrence of the specified
Unicode character in this string. The search starts at a specified
character position.
It will give you the starting and end index of your word. You can then highlight it!
int endIndex = resultsRichTextBox.Text.IndexOf(' ', novelOffset - 2);
resultsRichTextBox.Select(novelOffset - 2, (endIndex - (novelOffset - 2)) );
You only need to handle what happens if it doesn't find any space after the word. The endIndex value will be -1 if that happens. I would simply set the value of endIndex to searchString.Length.
int startIndex;
//fill startIndex with the known value
int endIndex = startIndex;
while(rtb.Text.CharAt(endIndex) != ' ' && endIndex < rtb.Text.Length)
{
endIndex++;
}
rtb.Select(startIndex, endIndex);
You can use a Find method given you provide the starting index of the word and look for the SPACE. Find will return you the index of next space and in fact the end of the word (found - 1).
You can then use a select call.
I am trying to solve the following problem but cannot find an elegant solution. Any ideas?
Thanks.
Input - a variable length string of numbers, e.g.,
string str = "5557476374202110373551116201";
Task - Check (from left to right) that each number (ignoring the repetitions) does not appear in the following 2 indexes. Using eg. above, First number = 5. Ignoring reps we see that last index of 5 in the group is 2. So we check next 2 indexes, i.e. 3 and 4 should not have 5. If it does we count it as error. Goal is to count such errors in the string.
In the above string errors are at indexes, 3,10 and 16.
in addition to the other excellent solutions you can use a simple regexp:
foreach (Match m in Regexp.Matches(str, #"(\d)(?!\1)(?=\d\1)"))
Console.WriteLine("Error: " + m.Index);
returns 3,10,16. this would match adjacent errors using lookahead with a backreference. handles repetitions. .net should support that. if not, you can use a non-backreference version:
(?<=0[^0])0|(?<=1[^1])1|(?<=2[^2])2|(?<=3[^3])3|(?<=4[^4])4|(?<=5[^5])5|(?<=6[^6])6|(?<=7[^7])7|(?<=8[^8])8|(?<=9[^9])9
A simple indexed for loop with a couple of look ahead if checks would work. You can treat a string as a char[] or as an IEnumerable - either way you can use that to loop over all of the characters and perform a lookahead check to see if the following one or two characters is a duplicate.
Sorry, not a C# man, but here's a simple solution in Ruby:
a="5557476374202110373551116201"
0.upto(a.length) do |i|
puts "error at #{i}" if a[i]!=a[i+1] && a[i]==a[i+2]
end
Output:
error at 3
error at 10
error at 16
Here's something I threw together in C# that worked with the example input from the question. I haven't checked it that thoroughly, though...
public static IEnumerable<int> GetErrorIndices(string text) {
if (string.IsNullOrEmpty(text))
yield break;
int i = 0;
while (i < text.Length) {
char c = text[i];
// get the index of the next character that isn't a repetition
int nextIndex = i + 1;
while (nextIndex < text.Length && text[nextIndex] == c)
nextIndex++;
// if we've reached the end of the string, there's no error
if (nextIndex + 1 >= text.Length)
break;
// we actually only care about text[nextIndex + 1],
// NOT text[nextIndex] ... why? because text[nextIndex]
// CAN'T be a repetition (we already skipped to the first
// non-repetition)
if (text[nextIndex + 1] == c)
yield return i;
i = nextIndex;
}
yield break;
}