This question already has answers here:
Word wrap a string in multiple lines
(7 answers)
How do I split a string by a multi-character delimiter in C#?
(10 answers)
Closed 6 years ago.
I want to split a string by a certain length, but I also want to make sure that it's a full word. For example, if I had:
string str = "Hello I have a dog ";
and I wanted to split it up into chunks of 5 I would do something like this (which I got from Split String into smaller Strings by length variable):
public IEnumerable<string> SplitByLength( string s, int length)
{
for (int i = 0; i < s.Length; i += length)
{
if (i + length <= s.Length)
{
yield return s.Substring(i, length);
}
else
{
yield return s.Substring(i);
}
}
}
but that would result in output like
"Hello"
"I Hav"
"e a d"
"og"
How could I adapt it so that it would split after 5 or after a whitespace? So I would get:
"Hello"
"I"
"Have"
It's not the best example but it's the best I could come up with off the top of my head. The reason I need it is that I'm displaying the results on a web page, and after a certain amount of words, it gets difficult to read due to a background image, so when it hits the limit it breaks a line but I don't want half of a word on one line and the other half on the next line.
You should use an if/else
if (i + length <= s.Length)
{
yield return s.Substring(i, length);
}
else if(s[i] == ' ')
{
yield return s.Substring(i, s.IndexOf(" ",i) - i);
}
else
{
yield return s.Substring(i);
}
Related
This question already has answers here:
What is an IndexOutOfRangeException / ArgumentOutOfRangeException and how do I fix it?
(5 answers)
Closed 3 months ago.
Hi just needed a little bit of help with a crash im having, so im putting together a little program that will work similar to a Caesar cipher by shifting the letters by a set value, however each subsequent letter is shifted to a different letter, rather then all letters being shifted by the same value (which is easy to crack with frequency analysis).
Anyway the program works fine if the word being encoded is shorter or the same length as the code (like a 7 letter word being encoded by a 7 digit code), but as soon as you try to encode a word longer than it, it crashes with an array out of bounds error or something.
What needs to happen is it needs to loop back around to the start of the code until no more letters need encoding.
```
```
static char ZipherEncode(char input, int shift)
{
char letter = (char)(input + shift);
if (letter > 'z')
{
letter = (char)(letter - 26);
}
else if (letter < 'a')
{
letter = (char)(letter + 26);
}
return letter;
}
static char ZipherDecode(char input, int shift)
{
char letter = (char)(input - shift);
if (letter > 'z')
{
letter = (char)(letter - 26);
}
else if (letter < 'a')
{
letter = (char)(letter + 26);
}
return letter;
}
int[] codeShift = new int[] { 4, 2, 6, 3, 0, 5, 1 };
Console.WriteLine("Please enter a word to encode: ");
string input = Console.ReadLine();
char[] zipherEncoded = new char[input.Length];
zipherEncoded = input.ToCharArray();
Console.WriteLine("\n\nENCODED: ");
int currCode = codeShift[0];
int counter = 0;
for (int i = 0; i < zipherEncoded.Length; i++)
{
if (zipherEncoded[i] != '\0')
{
//DEBUG
Console.WriteLine("WE ARE HERE!");
Console.Write("{0}", ZipherEncode(zipherEncoded[i], codeShift[i]));
}
else
{
//DEBUG
Console.WriteLine("WE ARE HERE (ELSE)!");
Console.Write("{0}", ZipherEncode(zipherEncoded[i], codeShift[currCode]));
//Console.Write("{0}", ZipherEncode(zipherEncoded[i], codeShift[counter]));
//Console.Write("{0}", ZipherEncode(zipherEncoded[i], Array.IndexOf(codeShift, currCode)));
counter++;
}
}
Console.ReadLine();
```
```
The output when I encode the word "volcano" reads -
ENCODED:
zqrfasp
This is correct, however when I try and encode "volcanocat", because the word is longer than the 7 digits in the code it crashes, the output should read -
ENCODED:
zqrfaspgcz
the "cat" part of the phrase should be encoded with a shift of 426 <<< loops back to the start of the codeShift array storing our shifts.
C (Shift of 4) > G
A (Shift of 2) > C
T (Shift of 6) > Z
As from the parts that are commented out you can see im trying to find a way to have it loop back around to the start of the shift code to finish off the final letters.
Im really new to C# so there may be a function built in to do what I want, but I cant get my head around it!
I think I cant see the forrest through the trees!
The problem is here:
ZipherEncode(zipherEncoded[i], codeShift[i])
In this code, i represents an index in the input string, but you're also using it as an index in the codeShift array. Since the input string may be longer than the array, you'll get an out of bounds error.
One way to resolve this would be to use a modulus operation (the% operator), which returns the remainder of a division. This can be used to always constrain the index to a value within the size of the codeShift array.
For example, let's pretend that the word has 6 characters but we only have 3 items in the codeShift array. We're fine for indexes 0, 1, and 2, but when we get to 3 we need to access the value at 0 again in the array. To do this, we can say:
int codeShiftIndex = i % codeShift.Length;
As we stated, codeShift has a length of 3, so when i is 3, i % 3 == 0 (the remainder of three divided by three), and when i is 4, i % 3 == 1, etc.
So your code change would look like:
ZipherEncode(zipherEncoded[i], codeShift[i % codeShift.Length])
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 years ago.
Improve this question
It's a little confusing but if you look at the example below you get it!
I have a special "Console.Write" method that takes a string, for example "§cHello %mThere!" and when printing to the Console, this method ignores the §c and %m (it changes the color of the Console).
Now, I have another method to print text by aligning it, by breaking the string into an array of strings every nth char. That means, if I pass a string of 100 chars and a LineLength of 10, it will break my string into an array of 10 strings with 10 chars each, then my Write method will print each one in a new line.
The problem is, when I split the text every nth char, it count the '§' and 'c' chars, and when I print it (the method for printing will remove those two), so the output is off by two chars.
So... I need a method that:
Splits a string into an array of strings every nth character.
However, it must not count '§' and the following char, or '%' and the next char as characters in that math.
The output must have those extra chars in the string array.
Example:
string Text = "§cOnce upon a time there was a §R%mnice girl named Cinderella. She was very poor and her father passed way."
int LineLength = 6;
return string[] Output = {
"§conce u" //[o n c e space u], thats 6 chars ignoring the first two.
"pon a " //[p o n space a space], thats 6 chars.
"time t" // etc
//etc
}
If someone help me write this, thanks in advance!!!
If I understand what you're saying this seems about right.
public static string[] ConsoleChunk(string input, int length){
List<string> Output = new List<string>();
int k = 0;
string currentString = "";
for(int i = 0; i < input.Length; i++){
if(k == 6){
Output.Add(currentString);
currentString = input[i].ToString();
k = 1;
}
else if(input[i] == '§' || input[i] == '%'){
currentString += input[i];
currentString += input[++i];
}
else{
k++;
currentString += input[i];
}
}
Output.Add(currentString);
return Output.ToArray();
}
Input
string test = "§cOnce upon a time there was a §R%mnice girl named Cinderella. She was very poor and her father passed way.";
Output
§cOnce u
pon a
time t
here w
as a §R%mn
ice gi
rl nam
ed Cin
derell
a. She
was v
ery po
or and
her f
ather
passed
way.
Given
public static IEnumerable<string> FunkyChunk(string source, int size)
{
var index = 0;
while (index < source.Length)
{
var sb = new StringBuilder(size*2);
for (int count = 0; count<size && index < source.Length; index++)
{
sb.Append(source[index]);
if (source[index] != '§' && source[index] != '%')
count++;
}
yield return sb.ToString();
}
}
Note : This is O(n) and used StringBuilder for less allocations even though there would be more succinct solutions. Using a fixed buffer and another index would likely be better
Usage
var input = "012345§678901234567%890123%4567890123456§§789012§345678901234";
foreach (var result in FunkyChunk(input,10))
Console.WriteLine(result);
Output
012345§6789
01234567%89
0123%456789
0123456§§789
012§3456789
01234
Full Demo Here
i have a string of length 98975333 and i need to remove first 5 letters in it. Can anyone suggest the best way to do this keeping performance in mind?
I tried
str.Substring(5,str.Length);
str.Remove(0,5);
which gives me result in 0.29 sec
but i want something even faster than the above.
Problem Using StringBuilder
-> i need to substring a part of the string and to do this i need to write
StringBuilder2.ToString().Substring(anyvaluehere)"
here the conversion of StringBuilder to string by ".ToString()" takes time and in this case i cant use StringBuilder
If you are working with long strings, always use StringBuilder. This class provides you fast adding and removing characters, faster than String.Concat or it's syntactic sugar "a" + "b". Moreover StringBuilder.ToString() method has special implementation for best performance as possible.
Sorry, c# strings are not arrays; they are immutable so extracting a (possibly very long) substring involves a copy.
However, most [string utilities] accept start and end indices, for instance IndexOf and CompareInfo.Compare all take a startIndexoverload.
Perhaps if you tell us what you want to do afterward we could suggest alternatives?
Update
Here are some ways you can write performant string parsing with the immutable strings in c#. Say for instance that you need to deserialize XML data inside the string, and need to skip the first N characters. You could do something like this:
public static object XmlDeserializeFromString<T>(this string objectData, int skip)
{
var serializer = new XmlSerializer(typeof(T));
using (var reader = new StringReader(objectData))
{
for (; skip > 0 && reader.Read() != -1; skip--)
;
return (T)serializer.Deserialize(reader);
}
}
As you can see from the source. StringReader.Read() does not make a copy of the unread portion of the string, it keeps an internal index to the remaining unread portion.
Or say you want to skip the first N characters of a string, then parse the string by splitting it at every "," character. You could write something like this:
public static IEnumerable<Pair<int>> WalkSplits(this string str, int startIndex, int count, params char[] separator)
{
if (string.IsNullOrEmpty(str))
yield break;
var length = str.Length;
int endIndex;
if (count < 0)
endIndex = length;
else
{
endIndex = startIndex + count;
if (endIndex > length)
endIndex = length;
}
while (true)
{
int nextIndex = str.IndexOfAny(separator, startIndex, endIndex - startIndex);
if (nextIndex == startIndex)
{
startIndex = nextIndex + 1;
}
else if (nextIndex == -1)
{
if (startIndex < endIndex)
yield return new Pair<int>(startIndex, endIndex - 1);
yield break;
}
else
{
yield return new Pair<int>(startIndex, nextIndex - 1);
startIndex = nextIndex + 1;
}
}
}
And then use the start and end indices of the Pair to further parse the string, or extract small substrings to feed to further parsing methods.
(Pair<T> is a small struct I created similar to KeyValuePair<TKey, TValue> but with identically typed first and second values. I can provide if needed.)
Using a StringBuilder to produce and manipulate the string will help you save on resources:
StringBuilder sb = new StringBuilder();
sb.Append("text"); //to add text in front
sb.Insert(50,"text"); // to insert text
sb.Remove(50,4); // to remove text
sb.ToString(); // to produce the string
If you have a fixed length of string that you wish to store elsewhere, you can make a char array and use StringBuilder's CopyTo() method:
e.g.
char[] firstfive = new char[5];
sb.CopyTo(0,firstfive,0,5);
Edit:
Actually, the OP figured this out himself, but I'm including it on the post for reference:
To get a portion of the StringBuilder as string:
sb.ToString(intStart,intLength)
Use String.Remove() i.e
String newStr = "";
newStr = str.Remove(0,5); //This will delete 5 characters starting from 0 index
Or
newStr = str.Remove(5); //Assumes the starting position as 0 and will ddelete 5 chars from that
Read more Here
I have a large string accepted from TCP listner which is in following format
"1,7620257787,0123456789,99,0922337203,9223372036,32.5455,87,12.7857,1/1/2012,9223372036:1,7620257787,0123456789,99,0922337203,9223372036,32.5455,87,12.7857:2/1/2012,234234234:3,7620257787,01234343456789,99,0922337203,9223372036,32.5455,87,12.7857,1/1/2012,9223372036:34,76202343457787,012434343456789,93339,34340922337203,9223372036,32.5455,87,12.7857,1/1/2012,9223372036"
You can see that this is a : seperated string which contains Records which are comma seperated fields.
I am looking for the best (fastest) way that split the string in given number of chunks and take care that one chunk should contain full record (string upto ':')
or other way of saying , there should not be any chunck which is not ending with :
e.g. 20 MB string to 4 chunks of 5 MB each with proper records (thus size of each chunk may not be exactly 5 MB but very near to it and total of all 4 chunks will be 20 MB)
I hope you can understand my question (sorry for the bad english)
I like the following link , but it does not take care of full record while spliting also don't know if that is the best and fastest way.
Split String into smaller Strings by length variable
I don't know how large a 'large string' is, but initially I would just try it with the String.Split method.
The idea is to divide the lenght of your data for the num of blocks required, then look backwards to search the last sep in the current block.
private string[] splitToBlocks(string data, int numBlocks, char sep)
{
// We return an array of the request length
if (numBlocks <= 1 || data.Length == 0)
{
return new string [] { data };
}
string[] result = new string[numBlocks];
// The optimal size of each block
int blockLen = (data.Length / numBlocks);
int idx = 0; int pos = 0; int lastSepPos = blockLen;
while (idx < numBlocks)
{
// Search backwards for the first sep starting from the lastSepPos
char c = data[lastSepPos];
while (c != sep) { lastSepPos--; c = data[lastSepPos]; }
// Get the block data in the result array
result[idx] = data.Substring(pos, (lastSepPos + 1) - pos);
// Reposition for then next block
idx++;
pos = lastSepPos + 1;
if(idx == numBlocks-1)
lastSepPos = data.Length - 1;
else
lastSepPos = blockLen * (idx + 1);
}
return result;
}
Please test it. I have not fully tested for fringe cases.
OK, I suggest you way with two steps:
Split string into chunks (see below)
Check chunks for completeness
Splitting string into chunks with help of linq (linq extension method taked from Split a collection into `n` parts with LINQ? ):
string tcpstring = "chunk1 : chunck2 : chunk3: chunk4 : chunck5 : chunk6";
int numOfChunks = 4;
var chunks = (from string z in (tcpstring.Split(':').AsEnumerable()) select z).Split(numOfChunks);
List<string> result = new List<string>();
foreach (IEnumerable<string> chunk in chunks)
{
result.Add(string.Join(":",chunk));
}
.......
static class LinqExtensions
{
public static IEnumerable<IEnumerable<T>> Split<T>(this IEnumerable<T> list, int parts)
{
int i = 0;
var splits = from item in list
group item by i++ % parts into part
select part.AsEnumerable();
return splits;
}
}
Am I understand your aims clearly?
[EDIT]
In my opinion, In case of performance consideration, better way to use String.Split method for chunking
It seems you want to split on ":" (you can use the Split method).
Then you have to add ":" after splitting to each chunk that has been split.
(you can then split on "," for all the strings that have been split by ":".
int index = yourstring.IndexOf(":");
string[] whatever = string.Substring(0,index);
yourstring = yourstring.Substring(index); //make a new string without the part you just cut out.
this is a general view example, all you need to do is establish an iteration that will run while the ":" character is encountered; cheers...
I need to solve the following question which i can't get to work by myself(newbie^^)..:
Ok, the question: Create a method which will print the central letter of a string (given as a parameter). I need to use the property lenght to determine the lenght.
So for example the string: Books. the middle/central letter is o.
Hope its a bit clear..
Thanks in advance.
Edit: I know how to determine the lenght of the string. Now the problem is to divide the word and then write down the next letter or something.
Here are some tips:
1. Type string has a Length property.
2 .If you know the index of the character you want, you can ask for it using: myString[index].
3. Knowing what to do with string that has even number of characters is necessary to answer that question.
4. Consider integer devision.
That should get you started.
string middleLetter(string arg)
{
return arg[arg.Length >> 1];
}
public static string FindMiddleChar(string s)
{
int middleChar = s.Length / 2;
if (s.Length > 2)
{
if (s.Length % 3 == 0)
{
if (s.Length <= 3)
{
return s[middleChar].ToString();
}
return s[middleChar - 1] + s[middleChar].ToString();
}
else if (s.Length % 3 != 0)
{
if (s.Length <= 4)
{
return s[middleChar - 1] + s[middleChar].ToString();
}
return s[middleChar].ToString();
}
}
return "Error, the input string must contain at least three characters.";
}