How to remove spaces using IndexOf? - c#

I created following to count number of words. Now I need to remove all spaces using IndexOf. I'm stuck. Can someone help? It has to be something simple, but I cant figure it out.
string text = "Hello. What time is it?";
int position = 0;
int noSpaces = 0;
for (int i = 0; i < text.Length; i++)
{
position = text.IndexOf(' ', position + 1);
if (position != -1)
{ noSpaces++; }
if (position == -1) break;
}
Console.WriteLine(noSpaces + 1);

If you are looking to just remove the spaces in your text so it would look like: Hello.Whattimeisit? then all you need to do is use String.Replace:
string text = "Hello. What time is it?";
string textWithNoSpaces = text.Replace(" ", "");
Console.WriteLine(textWithNoSpaces); // will print "Hello.Whattimeisit?"
If you are looking to split the text into separate words then you would want to use String.Split:
string text = "Hello. What time is it?";
string[] words = text.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); // "RemoveEmptyEntries" will remove any entries which are empty: ""
// words[0] > Hello.
// words[1] > What
// etc.
You then can get a count of how many words are in the text and then combine them, using String.Concat, if you need text in the form of Hello.Whattimeisit?:
int numberOfWords = words.Length;
string textWithNoSpaces = string.Concat(words);
Update: This is how you would count the number of words and remove spaces using String.IndexOf & String.Substring:
This is a really sloppy example, but it gets the job done
string text = "Hello. What time is it?";
string newText = string.Empty;
int prevIndex = 0;
int index1 = 0;
int index2 = 0;
int numberOfWords = 0;
while (true)
{
index1 = text.IndexOf(' ', prevIndex);
if (index1 == -1)
{
if (prevIndex < text.Length)
{
newText += text.Substring(prevIndex, (text.Length - prevIndex));
numberOfWords += 1;
}
break;
}
index2 = text.IndexOf(' ', (index1 + 1));
if ((index2 == -1) || (index2 > (index1 + 1)))
{
newText += text.Substring(prevIndex, (index1 - prevIndex));
numberOfWords += 1;
}
prevIndex = (index1 + 1);
}
Console.WriteLine(numberOfWords); // will print 5
Console.WriteLine(newText); // will print "Hello.Whattimeisit?"
Console.ReadLine();

If your requirement is to count the number of words, can't you try this?
string text = "Hello. What time is it?";
var arr = text.Split(' ');
var count = arr.Length;
.Net Fiddle

Strings are immutable so you cant achieve it with only IndexOf that will require multiple changes. if you need to achieve it with that particular method I think that StringBuilder is the only way. However if this is not some assignment and you plan to use it in real application I strongly dissuade because it is really process heavy.

Related

How to print occurrence of a character in string in alphabetical order in C#?

Can anyone help me to find most efficient way to print character occurrence along with that character in a given string in alphabetical order?
I am able to count occurrence of character in string but I am not able to sort it in alphabetical order.
string OutputString = string.Empty;
int count = 1;
char[] charArr = inputString.ToCharArray();
for (int i = 0; i < charArr.Length; i++) {
for (int j = i + 1; j < charArr.Length; j++) {
if (charArr[i] == charArr[j])
count++;
}
if (!OutputString.Contains(charArr[i]))
OutputString += charArr[i].ToString() + count.ToString();
count = 1;
}
OutputString = string.Concat(OutputString.OrderBy(c => c));
let's say input string in xgdgyd
output should be:
d2g2x1y1.
You can use Linq to simplify this:
string s = "xgdgyd";
var result = s
.GroupBy(c => c)
.Select(g => g.Key.ToString() + g.Count())
.OrderBy(x => x);
Console.WriteLine(string.Concat(result)); // Outputs "d2g2x1y1"
The most useful thing here is GroupBy(), which will group all identical items together. That allows us to use g.Count() to count the number of items in each group.
Then we just concatenate each group key (a char) with its count into a single string.
Example on .Net Fiddle.
(I've simplified the code to use string.Concat() rather than string.Join() here.)
Solution given by #Matthew with LINQ is perfect, but if you want a solution with for loops as you posted in question then do this.
sort inputString first, and remove the line of code that sorts OutputString at the end, like this::
string inputString = "xgdgyd";
inputString = string.Concat(inputString.OrderBy(c => c));
string OutputString = string.Empty;
int count = 1;
char[] charArr = inputString.ToCharArray();
for (int i = 0; i < charArr.Length; i++)
{
for (int j = i + 1; j < charArr.Length; j++)
{
if (charArr[i] == charArr[j])
count++;
}
if (!OutputString.Contains(charArr[i]))
OutputString += charArr[i].ToString() + count.ToString();
count = 1;
}
Since you might not yet know LINQ, here is a solution using "classic" techniques:
string input = "xgdgyd";
char[] charArr = input.ToCharArray();
Array.Sort(charArr); // Sort before counting as Gian Paolo suggests!
// ==> "ddggxy"
int count;
string output = "";
for (int i = 0; i < charArr.Length; i += count) { // Increment by count to get
// the next different char!
count = 1;
// Note that we can combine the conditions within the for-statement
for (int j = i + 1; j < charArr.Length && charArr[j] == charArr[i]; j++) {
count++;
}
output += charArr[i] + count.ToString();
}
Console.WriteLine(output); // ==> d2g2x1y1
Note that the increment i += count, which is equivalent to i = i + count is performed at the end of the for-loop. Therefore count will be initialized at this point.
Another variant that uses only one loop instead of two nested loops appends the previous character to the output and resets the counter as soon as a different character is found.
string input = "xgdgyd";
char[] charArr = input.ToCharArray();
Array.Sort(charArr); // Sort before counting as Gian Paolo suggests!
int count = 1;
string output = "";
for (int i = 1; i < charArr.Length; i++) {
if (charArr[i] == charArr[i - 1]) {
count++;
} else {
output += charArr[i - 1] + count.ToString();
count = 1;
}
}
// Output last char
output += charArr[charArr.Length - 1] + count.ToString();
Console.WriteLine(output);
A more advanced technique would be to use a StringBuilder. See Concatenating Strings Efficiently by Jon Skeet.

Split String but Return whole word at the end

I am using the following function to split a string into chunks
public static IList<string> SplitChunks(string text, int chunkSize)
{
List<string> chunks = new List<string>();
int offset = 0;
while (offset < text.Length)
{
int size = Math.Min(chunkSize, text.Length - offset);
chunks.Add(text.Substring(offset, size));
offset += size;
}
return chunks;
}
Works fine but the issue is in many cases the chunk ends with an incomplete word such as
Input:
String: Hello Everyone. How are you?
Size: 10
Output:
Hello Ever
where I want it to return a full last word such as Hello Everyone
How can I modify my function so the last word is a full word regardless of the size of the chunk
You could split the string into words and then try to generate chunks of at least chunkSize size:
public static IList<string> SplitChunks(string text, int chunkSize)
{
var words = text.Split(' ');
var result = new List<string>();
int length = 0;
string current = "";
foreach(var word in words)
{
current += word + " ";
length += word.Length + 1;
if (length > chunkSize) {
result.Add(current);
current = "";
length = 0;
}
}
if (current != "")
result.Add(current);
return result;
}
You could do something like this, but it's a bit ugly because it's producing a side effect in the TakeWhile:
int count = 0;
const string text = "Hello Everyone. How are you?";
var ret = text.TakeWhile(s =>
{
var keepTaking = count < max;
count += s.Length + 1; // +1 for the space between words
return keepTaking;
});
Try this one too:
public static IList<string> SplitChunks(string text, int chunkSize)
{
var parts = text.Split(' ');
return parts.Skip(1).Aggregate(parts.Take(1).ToList(), (a, x) =>
{
if ((a.Last() + x).Length > chunkSize)
a.Add(x);
else
a[a.Count - 1] += " " + x;
return a;
});
}
When I call SplitChunks("Hello Everyone. How are you?", 10) I get this:
Hello
Everyone.
How are
you?

Words in a rectangle c#

I am trying to create rectangle from stars and put inside a text, but I can't figure it out. Can anyone help me?
string s = Console.ReadLine();
string[] n = s.Split(' ');
int longest = 0;
for (int i = 0; i < n.Length; i++)
{
if(n[i].Length > longest)
{
longest = n[i].Length;
}
}
for (int i = 1; i <= n.Length + 2; i++)
{
for (int j = 1; j <= longest + 2; j++)
{
if (i == 1 || i == n.Length + 2 || j == 1 || j == longest + 2)
{
Console.Write("*");
}
if (i == 2 && j == 1)
{
Console.Write(n[0]);
}
else
Console.Write("");
}
Console.WriteLine();
}
Console.ReadLine();
I can put single word and it's fine but, if I will change the number of array index it doesn't work properly.
Thanks for help!
Multi word version
// please, think about variables' names: what is "n", "s"?
// longest is NOT the longest word, but maxLength
string text = Console.ReadLine();
// be nice: allow double spaces, take tabulation into account
string[] words = text.Split(new char[] { ' ', '\t' },
StringSplitOptions.RemoveEmptyEntries);
// Linq is often terse and readable
int maxLength = words.Max(word => word.Length);
// try keep it simple (try avoiding complex coding)
// In fact, we have to create (and debug) top
string top = new string('*', maxLength + 2);
// ... and body:
// for each word in words we should
// - ensure it has length of maxLength - word.PadRight(maxLength)
// - add *s at both ends: "*" + ... + "*"
string body = string.Join(Environment.NewLine, words
.Select(word => "*" + word.PadRight(maxLength) + "*"));
// and, finally, join top, body and top
string result = string.Join(Environment.NewLine, top, body, top);
// final output
Console.Write(result);
For the Hello My World! input the output is
********
*Hello *
*My *
*World!*
********

Split string into array of words

I want to split a string into an array of words without using string.Split. I tried already this code and it is working but cant assign the result into the array
string str = "Hello, how are you?";
string tmp = "";
int word_counter = 0;
for (int i = 0; i < str.Length; i++)
{
if (str[i] == ' ')
{
word_counter++;
}
}
string[] words = new string[word_counter+1];
for (int i = 0; i < str.Length; i++)
{
if (str[i] != ' ')
{
tmp = tmp + str[i];
continue;
}
// here is the problem, i cant assign every tmp in the array
for (int j = 0; j < words.Length; j++)
{
words[j] = tmp;
}
tmp = "";
}
You just need a kind of index pointer to put up your item one by one to the array:
string str = "Hello, how are you?";
string tmp = "";
int word_counter = 0;
for (int i = 0; i < str.Length; i++) {
if (str[i] == ' ') {
word_counter++;
}
}
string[] words = new string[word_counter + 1];
int currentWordNo = 0; //at this index pointer
for (int i = 0; i < str.Length; i++) {
if (str[i] != ' ') {
tmp = tmp + str[i];
continue;
}
words[currentWordNo++] = tmp; //change your loop to this
tmp = "";
}
words[currentWordNo++] = tmp; //do this for the last assignment
In my example the index pointer is named currentWordNo
Try using regular expressions, like this:
string str = "Hello, how are you?";
// words == ["Hello", "how", "are", "you"]
string[] words = Regex.Matches(str, "\\w+")
.OfType<Match>()
.Select(m => m.Value)
.ToArray();
String.Split is not a good option since there are too many characters to split on: ' ' (space), '.', ',', ';', '!' etc.
Word is not just a stuff between spaces, there are punctuations to consider, non-breaking spaces etc. Have a look at the input like this:
string str = "Bad(very bad) input to test. . ."
Note
Absence of space after "Bad"
Non-breaking space
Addition spaces after full stops
And the right output should be
["Bad", "very", "bad", "input", "to", "test"]
You can also use a List to create your words list:
string str = "Hello, how are you?";
string tmp = "";
List<string> ListOfWords = new List<string>();
int j = 0;
for (int i = 0; i < str.Length; i++)
{
if (str[i] != ' ')
{
tmp = tmp + str[i];
continue;
}
// here is the problem, i cant assign every tmp in the array
ListOfWords.Add(tmp);
tmp = "";
}
ListOfWords.Add(tmp);
In this way you can avoid to count the number of word and the code is more simple. Use ListOfWord[x] to read any word

highlight the '#' until line end in richtextbox

I have the following text in my RIchTextBox:
foo:baa#done baa
a:b#pending ee
and I want highlight all after # and before " "(espace)
How I do this? I tried make the end as IndexOf of \t or " " but it returns -1.
My code(not working as expected):
string[] lines = list.Lines;
string line;
for (int i = 0, max = lines.Length; i < max; i++)
{
line = lines[i];
int start = list.Find("#");
int end = ??? // I tried list.Find("\t") and list.Find(" ")
if (-1 != start || -1 != end)
{
list.Select(start, end);
list.SelectionColor = color;
}
}
list is an RichTextBox
Use GetLineFromCharIndex() to get the line number of the Find() method return value. Then GetFirstCharIndexFromLine(line + 1) to know where the next line starts. That gives you the SelectionStart and SelectionLength values you need to highlight the text.
try this:
string[] lines = list.Lines;
string line;
int len = 0;
for (int i = 0, max = lines.Length; i < max; i++)
{
line = lines[i];
int j = i == 0 ? 0 : len;
string str = Regex.Match(line, #"#.*$").Value;
if (!string.IsNullOrEmpty(str))
{
int start = list.Find(str, j, RichTextBoxFinds.None);
if (start != -1)
{
list.Select(start, str.Length);
list.SelectionColor = Color.Red;
}
len += line.Length;
}
}
Maybe you should use line.IndexOf instead of list.Find?
In short, you seem to be searching for characters in your List control, not in the string line.

Categories

Resources