I am basically just wondering how can I make this while loop repeat continuously forever? I just can't figure out how to do it. once it reaches the end of the string it throws an exception. I have tried goto but it didn't work idk if i was just using it in the wrong play or what but i could get it work.
private void checkBox2_CheckedChanged(object sender, EventArgs e)
{
if (this.checkBox2.Checked)
{
int startIndex = 0;
string str = "hiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii";
int length = str.Length;
while (true)
{
Application.DoEvents();
Thread.Sleep(200);
startIndex++;
string str2 = str.Substring(startIndex, 15);
label2.Text = str2;
if (startIndex == length)
{
startIndex = 0;
}
The last valid index in a string (or any array or list or collection) is always the length - 1, not length. Furthermore, since you are taking a substring of length 15, you actually want to stop 15 characters before the end. You'll want to change your if statement to be
if(startIndex == length - 16)
startIndex = 0;
Your while loop isn't the problem, it's your call to Substring.
Once startIndex becomes high enough, there aren't 15 more characters in the string...so Substring will thrown an ArgumentOutOfRangeException.
To fix the problem, you need to change your if statement to something like:
if(startIndex == length - 16)
if (startIndex + 15 == length)
{
startIndex = 0;
}
Related
I have the following sequence of numbers:
You can see that those numbers a lot. I want to shorten that string. Let's say if the string contains more than 20 numbers, it should display 18 numbers, then "..." and then the last two of the sequence.
I could probably do that by adding those numbers in a List<int> or HashSet<int> (HashSet might be faster in this case), but I think it will be slow.
StringBuilder temp = new StringBuilder();
for (...)
{
temp.Append($"{number} ");
}
var sequence = temp.ToString();
Example of what I want:
7 9 12 16 18 21 25 27 30 34 36 39 43 45 48 52 54 57 ... 952 954
Note that I want only fast ways.
This version is about 8 times faster than the other answers and allocates only about 6% as much memory. I think you'll be hard-pressed to find a faster version:
static string Truncated(string input)
{
var indexOfEighteenthSpace = IndexOfCharSeekFromStart(input, ' ', 18);
if (indexOfEighteenthSpace <= 0) return input;
var indexOfSecondLastSpace = IndexOfCharSeekFromEnd(input, ' ', 2);
if (indexOfSecondLastSpace <= 0) return input;
if (indexOfSecondLastSpace <= indexOfEighteenthSpace) return input;
var leadingSegment = input.AsSpan().Slice(0, indexOfEighteenthSpace);
var trailingSegment = input.AsSpan().Slice(indexOfSecondLastSpace + 1);
return string.Concat(leadingSegment, " ... ", trailingSegment);
static int IndexOfCharSeekFromStart(string input, char value, int count)
{
var startIndex = 0;
for (var i = 0; i < count; i++)
{
startIndex = input.IndexOf(value, startIndex + 1);
if (startIndex <= 0) return startIndex;
}
return startIndex;
}
static int IndexOfCharSeekFromEnd(string input, char value, int count)
{
var endIndex = input.Length - 1;
for (var i = 0; i < count; i++)
{
endIndex = input.LastIndexOf(value, endIndex - 1);
if (endIndex <= 0) return endIndex;
}
return endIndex;
}
}
Small individual steps
How do I make a list from this sequence (string)?
var myList = myOriginalSequence.Split(' ').ToList();
How do you take the first 18 numbers from a list?
var first18Numbers = myList.Take(18);
How do you take the last 2 numbers from a list?
var last2Numbers = myList.Skip(myList.Count() - 2);
How do you ensure that this is only done when there are more than 20 numbers in the list?
if(myList.Count() > 20)
How do you make a new sequence string from a list?
var myNewSequence = String.Join(" ", myList);
Putting it all together
var myList = myOriginalSequence.Split(' ').ToList();
string myNewSequence;
if(myList.Count() > 20)
{
var first18Numbers = myList.Take(18);
var first18NumbersString = String.Join(" ", first18Numbers);
var last2Numbers = myList.Skip(myList.Count() - 2);
var last2NumbersString = String.Join(" ", last2Numbers);
myNewSequence = $"{first18NumbersString} ... {last2NumbersString}"
}
else
{
myNewSequence = myOriginalSequence;
}
Console.WriteLine(myNewSequence);
Try this:
public string Shorten(string str, int startCount, int endCount)
{
//first remove any leading or trailing whitespace
str = str.Trim();
//find the first startCount numbers by using IndexOf space
//i.e. this counts the number of spaces from the start until startCount is achieved
int spaceCount = 1;
int startInd = str.IndexOf(' ');
while (spaceCount < startCount && startInd > -1)
{
startInd = str.IndexOf(' ',startInd +1);
spaceCount++;
}
//find the last endCount numbers by using LastIndexOf space
//i.e. this counts the number of spaces from the end until endCount is achieved
int lastSpaceCount = 1;
int lastInd = str.LastIndexOf(' ');
while (lastSpaceCount < endCount && lastInd > -1)
{
lastInd = str.LastIndexOf(' ', lastInd - 1);
lastSpaceCount++;
}
//if the start ind or end ind are -1 or if lastInd <= startIndjust return the str
//as its not long enough and so doesn't need shortening
if (startInd == -1 || lastInd == -1 || lastInd <= startInd) return str;
//otherwise return the required shortened string
return $"{str.Substring(0, startInd)} ... {str.Substring(lastInd + 1)}";
}
the output of this:
Console.WriteLine(Shorten("123 123 123 123 123 123 123 123 123 123 123",4,3));
is:
123 123 123 123 ... 123 123 123
I think this may help :
public IEnumerable<string> ShortenList(string input)
{
List<int> list = input.Split(" ").Select(x=>int.Parse(x)).ToList();
if (list.Count > 20)
{
List<string> trimmedStringList = list.Take(18).Select(x=>x.ToString()).ToList();
trimmedStringList.Add("...");
trimmedStringList.Add(list[list.Count-2].ToString());
trimmedStringList.Add(list[list.Count - 1].ToString());
return trimmedStringList;
}
return list.Select(x => x.ToString());
}
No idea what the speed on this would be like but as a wild suggestion, you said the numbers come in string format and it looks like they're seperated by spaces. You could get the index of the 19th space (to display 18 numbers) using any of the methods found here, and substring from index 0 to that index and concatenate 3 dots. Something like this:
numberListString.SubString(0, IndexOfNth(numberListString, ' ', 19)) + "..."
(Not accurate code, adding or subtracting indexes or adjusting values (19) may be required).
EDIT: Just saw that after the dots you wanted to have the last 2 numbers, you can use the same technique! Just concatenate that result again.
NOTE: I used this whacky technique because the OP said they wanted fast ways, I'm just offering a potential option to benchmark :)
There is an alternative way that prevents iteration through the entire string of numbers and is reasonably fast.
Strings in .NET are basically an array of chars, and can be referenced on an individual basis using array referencing ([1..n]). This can be used to our advantage by simply testing for the correct number of spaces from the start and end respectively.
There are no niceties in the code, but they could be optimised later (for instance, by ensuring that there's actually something in the string, that the string is trimmed etc.).
The functions below could also be optimised to a single function if you're feeling energetic.
string finalNumbers = GetStartNumbers(myListOfNumbers, 18);
if(finalNumbers.EndsWith(" ... "))
finalNumbers += GetEndNumbers(myListOfNumbers, 2);
public string GetStartNumbers(string listOfNumbers, int collectThisManyNumbers)
{
int spaceCounter = 0; // The current count of spaces
int charPointer = 0; // The current character in the string
// Loop through the list of numbers until we either run out of characters
// or get to the appropriate 'space' position...
while(spaceCounter < collectThisManyNumbers && charPointer <= listOfNumbers.Length)
{
// The following line will add 1 to spaceCounter if the character at the
// charPointer position is a space. The charPointer is then incremented...
spaceCounter += ( listOfNumbers[charPointer++]==' ' ? 1 : 0 );
}
// Now return our value based on the last value of charPointer. Note that
// if our string doesn't have the right number of elements, then it will
// not be suffixed with ' ... '
if(spaceCounter < collectThisManyNumbers)
return listOfNumbers.Substring(0, charPointer - 1);
else
return listOfNumbers.Substring(0, charPointer - 1) + " ... ";
}
public string GetEndNumbers(string listOfNumbers, int collectThisManyNumbers)
{
int spaceCounter = 0; // The current count of spaces
int charPointer = listOfNumbers.Length; // The current character in the string
// Loop through the list of numbers until we either run out of characters
// or get to the appropriate 'space' position...
while(spaceCounter < collectThisManyNumbers && charPointer >= 0)
{
// The following line will add 1 to spaceCounter if the character at the
// charPointer position is a space. The charPointer is then decremented...
spaceCounter += ( listOfNumbers[charPointer--]==' ' ? 1 : 0 );
}
// Now return our value based on the last value of charPointer...
return listOfNumbers.Substring(charPointer);
}
Some people find the use of ++ and -- objectionable but it's up to you. If you want to do the maths and logic, knock yourself out!
Please note that this code is quite long because it's commented to the far end of a fart.
An exception:
Index was outside the bounds of the array
gets thrown in the if below or the else below that
public static Int64[] PrimeGenerator(Int64 length = 1)
{
Int64 pos = 0;
Int64[] primes = new Int64[length];
Int64 Cprime = 2;
Int64 controller = 0;//On evens it adds one less than, on odds it adds oone more than
while(length >= 0)
{
if(pos == 0)
{
primes[pos] = 2;
goto End;
}
if(controller % 2 == 0)
{
primes[pos] = (2 * Cprime - 1);
}
else
{
primes[pos] = (2 * Cprime + 1);
}
End:
Cprime = primes[pos];
controller++;
pos++;
length--;
}
return primes;
}
I have lookat the visual studio debugger and it says that Cprime is some crazy negative number and that length is 0 when it should not be
When I changed all the Int64's to UInt64's Cprime is some crazy positive integer and length is still zero
The code calling this code looks like this, print is a renamed Console.WriteLine
static void Main()
{
UInt64 p = 1000;
UInt64[] primes = PrimeGenerator(p);
bool[] truth = BadArrayTest(primes);
foreach(bool tru in truth)
{
print(tru);
}
System.Threading.Thread.Sleep(50000);
Environment.Exit(0);
}
just do this
while(length > 0)
index is zero base that means starts from zero but length is not like that
so you always have one more loop cycle which is out of array length.
Your array is of length, but you run thru the loop length+1 times. By the way, never ever use Goto.
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.
I want to know how can I replace a character of a string with condition of "except last number characters"?
Example:
string = "4111111111111111";
And I want to make it that
new_string = "XXXXXXXXXXXXX1111"
In this example I replace the character to "X" except the last 4 characters.
How can I possibly achieve this?
Would that suit you?
var input = "4111111111111111";
var length = input.Length;
var result = new String('X', length - 4) + input.Substring(length - 4);
Console.WriteLine(result);
// Ouput: XXXXXXXXXXXX1111
How about something like...
new_string = new String('X', YourString.Length - 4)
+ YourString.Substring(YourString.Length - 4);
create a new string based on the length of the current string -4 and just have it all "X"s. Then add on the last 4 characters of the original string
Here's a way to think through it. Call the last number characters to leave n:
How many characters will be replaced by X? The length of the string minus n.
How can we replace characters with other characters? You can't directly modify a string, but you can build a new one.
How to get the last n characters from the original string? There's a couple ways to do this, but the simplest is probably Substring, which allows us to grab part of a string by specifying the starting point and optionally the ending point.
So it would look something like this (where n is the number of characters to leave from the original, and str is the original string - string can't be the name of your variable because it's a reserved keyword):
// 2. Start with a blank string
var new_string = "";
// 1. Replace first Length - n characters with X
for (var i = 0; i < str.Length - n; i++)
new_string += "X";
// 3. Add in the last n characters from original string.
new_string += str.Substring(str.Length - n);
This might be a little Overkill for your ask. But here is a quick extension method that does this.
it defaults to using x as the masking Char but can be changed with an optional char
public static class Masking
{
public static string MaskAllButLast(this string input, int charsToDisplay, char maskingChar = 'x')
{
int charsToMask = input.Length - charsToDisplay;
return charsToMask > 0 ? $"{new string(maskingChar, charsToMask)}{input.Substring(charsToMask)}" : input;
}
}
Here a unit tests to prove it works
using Xunit;
namespace Tests
{
public class MaskingTest
{
[Theory]
[InlineData("ThisIsATest", 4, 'x', "xxxxxxxTest")]
[InlineData("Test", 4, null, "Test")]
[InlineData("ThisIsATest", 4, '*', "*******Test")]
[InlineData("Test", 16, 'x', "Test")]
[InlineData("Test", 0, 'y', "yyyy")]
public void Testing_Masking(string input, int charToDisplay, char maskingChar, string expected)
{
//Act
string actual = input.MaskAllButLast(charToDisplay, maskingChar);
//Assert
Assert.Equal(expected, actual);
}
}
}
StringBuilder sb = new StringBuilder();
Char[] stringChar = string.toCharArray();
for(int x = 0; x < stringChar.length-4; x++){
sb.append(stringChar[x]);
}
sb.append(string.substring(string.length()-4));
string = sb.toString();
I guess you could use Select with index
string input = "4111111111111111";
string new_string = new string(input.Select((c, i) => i < input.Length - 4 ? 'X' : c).ToArray());
Some of the other concise answers here did not account for strings less than n characters. Here's my take:
var length = input.Length;
input = length > 4 ? new String('*', length - 4) + input.Substring(length - 4) : input;
lui,
Please Try this one...
string dispString = DisplayString("4111111111111111", 4);
Create One function with pass original string and no of digit.
public string DisplayString(string strOriginal,int lastDigit)
{
string strResult = new String('X', strOriginal.Length - lastDigit) + strOriginal.Substring(strOriginal.Length - lastDigit);
return strResult;
}
May be help you....
Try this:
String maskedString = "...."+ (testString.substring(testString.length() - 4, testString.length()));
Late to the party but I also wanted to mask all but the last 'x' characters, but only mask numbers or letters so that any - ( ), other formatting, etc would still be shown. Here's my quick extension method that does this - hopefully it helps someone. I started with the example from Luke Hammer, then changed the guts to fit my needs.
public static string MaskOnlyChars(this string input, int charsToDisplay, char maskingChar = 'x')
{
StringBuilder sbOutput = new StringBuilder();
int intMaskCount = input.Length - charsToDisplay;
if (intMaskCount > 0) //only mask if string is longer than requested unmasked chars
{
for (var intloop = 0; intloop < input.Length; intloop++)
{
char charCurr = Char.Parse(input.Substring(intloop, 1));
byte[] charByte = Encoding.ASCII.GetBytes(charCurr.ToString());
int intCurrAscii = charByte[0];
if (intloop <= (intMaskCount - 1))
{
switch (intCurrAscii)
{
case int n when (n >= 48 && n <= 57):
//0-9
sbOutput.Append(maskingChar);
break;
case int n when (n >= 65 && n <= 90):
//A-Z
sbOutput.Append(maskingChar);
break;
case int n when (n >= 97 && n <= 122):
//a-z
sbOutput.Append(maskingChar);
break;
default:
//Leave other characters unmasked
sbOutput.Append(charCurr);
break;
}
}
else
{
//Characters at end to remain unmasked
sbOutput.Append(charCurr);
}
}
}
else
{
//if not enough characters to mask, show unaltered input
return input;
}
return sbOutput.ToString();
}
The code below belongs to a binary search algorithm. The user enters numbers in textbox1 and enters the number that he want to find with binarysearch in textbox2. When I enter for example 16 in textBox2 and put breakpoint on the line I commented, I see that the value of searchnum is 10.
I think it converts to hexadecimal. I don't know why. Can you help me?
private void button1_Click(object sender, EventArgs e)
{
string[] source = textBox1.Text.Split(',');
int[] nums = new int[source.Length];
for (int i = 0; i < source.Length; i++)
{
nums[i] = Convert.ToInt32(source[i]);
}
string str_searchnum = textBox2.Text;
int searchnum = Convert.ToInt32(str_searchnum); // str_searchnum shows the value 16 but searchnum shows 10
int first = 0;
int last = nums.Length - 1;
while (1 < nums.Length - 1)
{
int mid = (int)Math.Floor(first + last / 2.0);
////if (first < last)
////{
//// break;
////}
if (searchnum < nums[mid])
{
last = mid - 1;
}
if (searchnum > nums[mid])
{
first = mid + 1;
}
else
{
MessageBox.Show(nums[mid].ToString());
}
}
}
Check to see if the debugger is set to display values using hexadecimal notation? You can find this option by right clicking in the watch window.
If that's not it, step through the entire method. What is the value of str_searchnum?
Although I personally prefer int.TryParse(), Convert.ToInt32() should be well-tested and not be doing any base conversions.
Why not use Array.BinarySearch? Also, your loop condition is (probably) wrong.