Search a word in the given string in C#? - c#

I have to find subtext in text without using builtin function of string.
public static void Main(string[] args)
{
string subtext = "polly";
string text = "polly put the katle on,polly put the katle on,polly put the katle on,we all have tea";
int i, j, found;
int strLen, wordLen;
strLen = text.Length;
wordLen = subtext.Length;
for (i = 0; i < strLen - wordLen; i++)
{
found = 1;
for (j = 0; j < wordLen; j++)
{
if (text[i + j] != subtext[j])
{
found = 0;
break;
}
}
if (found == 1)
{
Console.WriteLine(" found at index:", subtext, i);
Console.ReadLine();
}
}
}

I am not sure how long you would like to search, your current code seems to find all indexes (or at least that seems to be the intent)
Some things you could change however is instead of always starting the loop, you could validate the if the char at position i matches the first char of the subtext, and if not continue.
When you want to write the data to the console, don't forget to add the spaceholders for your arguments, like:
Console.WriteLine("found {0} at index: {1}", subtext, i);
For the rest, I guess your current implementation is okay, but you could add some validations, like ensuring that both texts are available, and if subtext is longer than the text, simply return -1 directly.
For a simple find of first index, I wrote this one up, it still looks pretty similar to yours
private static int FindIn( string text, string sub ) {
if (string.IsNullOrWhiteSpace( text ) || string.IsNullOrWhiteSpace( sub ) ) {
return string.IsNullOrWhiteSpace( sub ) ? 0 : -1;
}
if (text.Length < sub.Length) {
return -1;
}
for (int i = 0; i < text.Length - sub.Length; i++) {
if (text[i] != sub[0]) {
continue;
}
var matched = true;
for (int j = 1; j < sub.Length && i + j < text.Length; j++) {
if (text[i+j] != sub[j]) {
matched = false;
break;
}
}
if (matched) {
return i;
}
}
return -1;
}
Which you can play around with here

There are a lot of pattern-matching algorithms in this book, i will leave here c# implementation of Knuth-Morris-Pratt algorithm.
static int[] GetPrefix(string s)
{
int[] result = new int[s.Length];
result[0] = 0;
int index = 0;
for (int i = 1; i < s.Length; i++)
{
while (index >= 0 && s[index] != s[i]) { index--; }
index++;
result[i] = index;
}
return result;
}
static int FindSubstring(string pattern, string text)
{
int res = -1;
int[] pf = GetPrefix(pattern);
int index = 0;
for (int i = 0; i < text.Length; i++)
{
while (index > 0 && pattern[index] != text[i]) { index = pf[index - 1]; }
if (pattern[index] == text[i]) index++;
if (index == pattern.Length)
{
return res = i - index + 1;
}
}
return res;
}

If you are looking for all occurance of the subtect in the text you can use the following code:
public static void Main(string[] args)
{
string subtext = "polly";
string text = "polly put the katle on,polly put the katle on,polly put the katle on,we all have tea";
int index = 0;
int startPosition = 0;
bool found = false;
while (index < text.Length - 1)
{
if (subtext[0] == text[index])
{
startPosition = index;
index++;
for (int j = 1; j <= subtext.Length - 1; j++)
{
if (subtext[j] != text[index])
{
found = false;
break;
}
else
{
found = true;
}
index++;
}
}
if (found)
{
Console.WriteLine("{0} found at index: {1}", subtext, startPosition);
found = false;
}
index++;
}
Console.ReadLine();
}
If you are looking only for the first occurance add break in the "if (found)" condition

Related

Count Matching Subsequences

This is what I need to do:
Create a function that receives a text string, and a search string, and returns how many times the search string appears in the string, as a subsequence of its letters in order.
For example, if you receive the word "Hhoola" and the substring "hola", the answer would be 4, because you could take the first H with the first O (and with the L and with the A), the first H with the second O, the second H with the first O, or the second H with the second O. If you receive "hobla", the answer would be 1. If you receive "ohla", the answer would be 0, because after the H there is no O to complete the sequence in order.
This is what i got so far:
int count = 0;
void Function(string text, string subText)
{
for (int i = 0; i < text.Length; i++)
{
if (text[i] == subText[0])
{
for (int j = 0; j < subText.Length; j++)
{
if (text[i + j] != subText[j])
{
break;
}
if (j == subText.Length - 1)
{
count++;
}
}
}
}
}
string text = Console.ReadLine().ToLower();
string subText = Console.ReadLine().ToLower();
ReceibeText(text, subText);
The code should look like this. Code doesn't work but is close.
public class SubSequences
{
string input = "";
string word = "";
int count = 0;
public void FindMatches(string input, string word)
{
this.input = input;
this.word = word;
FindMatchesRecursive(0, 0);
}
public void FindMatchesRecursive(int inputIndex, int wordIndex)
{
for (int i = inputIndex; i < input.Length - word.Length; i++ )
{
for (int j = wordIndex; j < input.Length - word.Length; j++)
{
if (word.Substring(i) == input.Substring(j))
{
if (j == word.Length)
{
FindMatchesRecursive(i + 1, j + 1);
}
else
{
Console.WriteLine("Word Matches");
}
}
}
}
}

C# return string in Sine-Wave format

I'm trying to create a function which will return string in Triangle Sine-Wave format:
but currently, my format is only in Wave format:
Code below:
public static void printWave(string str)
{
int height = 3;
// Get length of the string
int len = str.Length;
// Create a 2d character array
char[,] matrixArray = new char[height, len];
char[] charArray = str.ToCharArray();
// for counting the
// rows of the ZigZag
int row = 0;
bool down = true;
for (int i = 0; i < len; i++)
{
// put characters
// in the matrix
matrixArray[row, i] = charArray[i];
// You have reached the bottom
if (row == height - 1)
down = false;
else if (row == 0)
down = true;
if (down)
row++;
else
row--;
}
// Print the Zig-Zag String
for (int i = 0; i < height; i++)
{
for (int j = 0; j < len; j++)
{
Console.Write(matrixArray[i, j] + " ");
}
Console.Write("\n");
}
}
Can you please help me modify my code to it will return triangle sin wave format?
We can use 3 separate StringBuilders to append to depending on our boolean top and a simple even value comparison. A quick TL;DR is that anything at an even index goes in the middle row, and then we flip between appending to the top or bottom row:
public static void printWave(string str)
{
//for use to determine top or bottom StringBuilder
bool top = true;
//will be used to generate each row of the output
StringBuilder topString = new StringBuilder();
StringBuilder middleString = new StringBuilder();
StringBuilder bottomString = new StringBuilder();
//iterate through paramter string
for (int i = 0; i < str.Length; i++)
{
//if char is at an even index, it goes in the middle StringBuilder, blank spaces in top and bottom builders
if (i%2 == 0)
{
topString.Append(" ");
middleString.Append(str[i]);
bottomString.Append(" ");
}
//if not even index, determine top or bottom row
else
{
//simply check our boolean and then flip it after use
if (top)
{
topString.Append(str[i]);
middleString.Append(" ");
bottomString.Append(" ");
top = false;
}
else
{
topString.Append(" ");
middleString.Append(" ");
bottomString.Append(str[i]);
top = true;
}
}
}
//write each row of strings on new lines
Console.WriteLine(topString.ToString());
Console.WriteLine(middleString.ToString());
Console.WriteLine(bottomString.ToString());
}
For a variable height:
public static void printWave(string str)
{
//height we want the wave to reach
int height = 5;
//determine "middle" row
int startingRow = height / 2;
int currentRow = startingRow; //this one is for modifying inside loop
bool up = true;
//2D array to hold the rows
char[,] arr = new char[height, str.Length];
for (int i = 0; i < str.Length; i++)
{
for (int j = 0; j < height; j++)
{
if (j == currentRow)
{
arr[j, i] = str[i];
}
else
arr[j, i] = ' ';
}
//could probably break this into more digestible pieces if time to think about it
if (up)
{
if (currentRow == 0)
{
up = false;
currentRow++;
}
else
{
currentRow--;
}
}
else
{
if (currentRow == height - 1)
{
up = true;
currentRow--;
}
else
{
currentRow++;
}
}
}
for (int k = 0; k < height; k++)
{
for (int l = 0; l < str.Length; l++)
{
Console.Write(arr[k, l]);
}
Console.WriteLine();
}
}
Examples of height = 5 and height = 6 output:
And finally, height = 7
This version works, but it's hard-coded to just the 3 rows like the question shows. If larger waves are needed, or especially if the size of the wave depends on the input string, then this may be hard to adjust to the requirements.
public static void PrintWave(string str)
{
printWithRowLogic(str, (i) => (i - 1) % 4 == 0);
Console.WriteLine();
printWithRowLogic(str, (i) => i % 2 == 0);
Console.WriteLine();
printWithRowLogic(str, (i) => (i - 3) % 4 == 0);
}
private static void printWithRowLogic(string str, Func<int, bool> checkLogic)
{
for (int i = 0; i < str.Length; i++)
Console.Write(checkLogic(i) ? str[i] : ' ');
}

Largest substring composed of identical characters

I want to develop method that will return the length of largest substring composed of identical characters form string that is passed as argument, but without using any of .NET libraries.
For example if we pass aaacccccdefffgg as parameter the biggest substring is ccccc and method should return 5.
Here is my working solution :
public static int GetMaxSubstringLenght(char[] myArray)
{
int max = 0;
for (int i = 0; i < myArray.Length-1; i++)
{
if (myArray.Length == 0)
{
return 0;
}
else
{
int j = i + 1;
int currentMax = 1; // string has some value, so we start with 1
while (myArray[i] == myArray[j])
{
currentMax++;
if (max < currentMax)
{
max = currentMax;
}
j++;
}
}
}
return max;
}
The code above will return expected result, but there will be some unnecessary iteration in for loop that I want to avoid. In first iteration when i=0it will compare it until j=2 and then will get out of while loop and start second iteration in for loop comparing the one at [1] index with [2], which we already did in previous iteration.So basically, when first iteration is completed, next one should start from the last value of j. How can I achieve that ?
Thank You in advance.
Since you want "Largest substring..." let's take String as argument and return String
public static String GetMaxSubstring(String value) {
if (String.IsNullOrEmpty(value))
return "";
int bestCount = 0;
char bestChar = '\0';
int currentCount = 0;
char current = '\0';
for (int i = 0; i < value.Length; ++i) {
if ((i == 0) || (value[i] != current))
currentCount = 0;
currentCount += 1;
current = value[i];
if (currentCount > bestCount) {
bestCount = currentCount;
bestChar = current;
}
}
return new String(bestChar, bestCount);
}
....
// "ccccc"
String result = GetMaxSubstring("aaacccccdefffgg");
// 5
int length = result.Length;
Another approach:
public static int MaxSubstringLength(string s)
{
if (string.IsNullOrEmpty(s))
return 0;
int max = 0, cur = 1;
for (int i = 1; i < s.Length; ++i, ++cur)
{
if (s[i] != s[i-1])
{
max = cur > max ? cur : max;
cur = 0;
}
}
return cur > max ? cur : max;
}
[EDIT] Simplified the code.
[EDIT2] Simplified the code further.
you also can do it with one loop:
public static int GetMaxSubstringLenght(char[] myArray)
{
int max = 0;
char currentchar = myArray[0];
int count = 1;
for each(char c in myArray)
{
if(currentchar != c)
{
count = 1;
currentchar = c;
}
if(count > max)
{
max = count;
}
count++;
}
return max;
}
I changed the code... now this code does not use math.max and I think I eleminated the mistake... I've no IDE at the moment to test it
public static int GetMaxSubstringLenght(char[] myArray)
{
if (myArray.Length == 0)
return 0;
if (myArray.Length == 1)
return 1;
int max = 1;
int localMax = 1;
for (int i = 0; i < myArray.Length - max; i++ )
{
if (myArray[i] == myArray[i + 1])
{
localMax++;
}
else
{
max = Math.Max(max, localMax);
localMax = 1;
}
}
return Math.Max(max, localMax);
}
static int LongestCharSequence(string s)
{
if (string.IsNullOrEmpty(s)) return 0;
var prevChar = '\0';
int cmax = 0;
int max = 1;
foreach (char c in s)
{
if (c != prevChar)
{
cmax = 1;
prevChar = c;
}
else
{
if (++cmax > max) max = cmax;
}
}
return max;
}
recursion!
static int LongestCharSequence(string s)
{
int i = (s?.Length ?? 0) == 0 ? 0 : 1;
for (; i < s?.Length; i++)
if (s[i] != s[i - 1]) return Math.Max(i, LongestCharSequence(s.Substring(i)));
return i;
}
Another solution using my favorite nested loop technique:
public static int MaxSubstringLength(string s)
{
int maxLength = 0;
for (int length = s != null ? s.Length : 0, pos = 0; pos < length;)
{
int start = pos;
while (++pos < length && s[pos] == s[start]) { }
maxLength = Math.Max(maxLength, pos - start);
}
return maxLength;
}

StackOverflow exception in a recursive method

I've written a recursive method in C# that should indent strings. For example, this string:
for (int i = 0; i < sb.Length; i++)
{
if (sb[i] == '{')
{
startIndex = i;
break;
}
}
should be converted to:
for (int i = 0; i < sb.Length; i++)
{
if (sb[i] == '{')
{
startIndex = i;
break;
}
}
My method is (updated):
private static string IndentText(string t,bool first = true)
{
if (first == false)
{
t = t.PadLeft(2);
}
int startIndex = t.IndexOf('{') + 1;
int stopIndex = t.LastIndexOf('}') - 1;
int blockLength = stopIndex - startIndex + 1;
if (blockLength <= 1 )
{
return "";
}
string start = t.Substring(0, startIndex);
string end = t.Substring(stopIndex + 1);
string indentBlock = t.Substring(startIndex, blockLength);
if (!CheckNestedBlocks(indentBlock))
{
return indentBlock;
}
return start + IndentText(indentBlock,false) + end;
}
private static bool CheckNestedBlocks(string t)
{
for (int i = 0; i < t.Length; i++)
{
if (t[i] == '{') // { and } always come in pairs, so I can check of only one of then
{
return true;
}
}
return false;
}
But I'm getting a StackOverflow exception in mscorlib.dll
What is my mistake? Thanks in advance.
By the way, because I think I'm complicating this problem, is there a better (and working) way to indent strings like this?
You should not include the braces in the "block" that is passed in the recursive call:
if (t[i] == '{')
{
startIndex = i + 1; // Start one character beyond {
break;
}
// ...
if (t[i] == '}')
{
stopIndex = i - 1; // Stop one character prior to }
break;
}

Find out how long the longest sequence is in a string

I recently had this question in an interview and this is what I came up with. Any feedback?
Find out how long the longest sequence is in a string. For example, in the string "abccdeeeeef" the answer would be 5.
static int LongestSeq(string strPass)
{
int longestSeq = 0;
char[] strChars = strPass.ToCharArray();
int numCurrSeq = 1;
for (int i = 0; i < strChars.Length - 1; i++)
{
if (strChars[i] == strChars[i + 1])
{
numCurrSeq++;
}
else
{
numCurrSeq = 1;
}
if (longestSeq < numCurrSeq)
{
longestSeq = numCurrSeq;
}
}
return longestSeq;
}
This will return 0 for strings of length 1 (when it should return 1).
First comment: you don't need to convert it to a char array. You can index straight into the string.
Second comment: you could easily generalize this to IEnumerable<T> if you wanted to, using foreach and remembering the "current" item.
Third comment: I think the comparison between longestSeq and numCurrSeq would be clearer as:
if (numCurrSeq > longestSeq)
To me that's more natural as I usually have the varying part of the expression first.
Just to add my 2 pence in, here's an alternative using Regex:
string source = "eeabccdeeeeef";
Regex reg = new Regex(#"(\w)\1+");
MatchCollection matches = reg.Matches(source);
int longest = 0;
foreach (System.Text.RegularExpressions.Match match in matches)
{
if (longest < match.Length) longest = match.Length;
}
Due to not reading the question properly in the first place when posting my previous answer, I should probably add in some actual feedback considering that's the question posted by the OP. However, every point I've come up with has been mentioned by Henrik or Job Skeet, so I'll just stress the point Jon Skeet made; you do not have to convert a string to a char array, you can just index a particular point in the string as follows:
char letter = someString[4];
So it should all still work if you replace strChars with strPass.
You can always rember the last character, so you don't need to access the array twice in an iteration.
Inside your loop you can use another loop which iterates as long as the current character is the same as the last character. After this subloop you can place the check if the current numCurrSeq > longestSeq you you don't need this check every iteration but for every subsequence.
I don't really know whatever langauge this is (C#?) so excuse any minor syntactic glitches (I don't know if it's "else if" or "elseif" or "elif" or something else)
static int LongestSeq(string strPass)
{
int longestSeq = 1;
int curSeqStart = 0;
for (int i = 1; i < strPass.Length; i++)
{
if (strPass[i] != strPass[curSeq])
{
curSeqStart = i;
}
else if (i - curSeqStart + 1 > longestSeq)
{
longestSeq = i - curSeqStart + 1;
}
}
return longestSeq;
}
It might be more efficient to do
...
else
{
len = i - curSeqStart + 1
if ( len > longestSeq )
{
longestSeq = len;
}
}
or even just
...
else
{
longestSeq = max(longestSeq, i - curSeqStart + 1)
}
depending on how good your 'max' implementation and compiler are.
I think this works? I don't ussually write recursive methods, I would have totally come up with the posters answer..
public static int recurse(Char last, int seqLength, int currentIndex, int largestSeqLength, string source)
{
if (currentIndex > source.Length)
{
return largestSeqLength;
}
if (source[currentIndex] == last)
{
seqLength++;
if (seqLength > largestSeqLength)
{
largestSeqLength = seqLength;
}
}
else
{
seqLength = 1;
}
return recurse(source[currentIndex], seqLength, currentIndex++, largestSeqLength, source);
}
And another implementation
public static int LongestSeq<T>(this IEnumerable<T> source)
{
if (source == null)
throw new ArgumentNullException("source");
int result = 0;
int currentCount = 0;
using (var e = source.GetEnumerator())
{
var lhs = default(T);
if (e.MoveNext())
{
lhs = e.Current;
currentCount = 1;
result = currentCount;
}
while (e.MoveNext())
{
if (lhs.Equals(e.Current))
{
currentCount++;
}
else
{
currentCount = 1;
}
result = Math.Max(currentCount, result);
lhs = e.Current;
}
}
return result;
}
A simple (untested) solution would be:
int GetLongestSequence(string input)
{
char c = 0;
int maxSequenceLength = 0;
int maxSequenceStart = 0;
int curSequenceLength = 0;
int length = input.Length;
for (int i = 0; i < length; ++i)
{
if (input[i] == c)
{
++curSequenceLength;
if (curSequenceLength > maxSequenceLength)
{
maxSequenceLength = curSequenceLength;
maxSequenceStart = i - (curSequenceLength - 1);
}
}
else
{
curSequenceLength = 1;
c = input[i];
}
}
return maxSequenceStart;
}
Or a better structured code (also untested):
private int GetSequenceLength(string input, int start)
{
int i = start;
char c = input[i];
while (input[i] == c) ++i; // Could be written as `while (input[i++] == c);` but i don't recommend that
return (i - start);
}
public int GetLongestSequence(string input)
{
int length = input.Length;
int maxSequenceLength = 0;
int maxSequenceStart = 0;
for (int i = 0; i < length; /* no ++i */)
{
int curSequenceLength = this.GetSequenceLength(input, i);
if (curSequenceLength > maxSequenceLength)
{
maxSequenceLength = curSequenceLength;
maxSequenceStart = i;
}
i += curSequenceLength;
}
return maxSequenceStart;
}
This extension method find the longest sequence of same characters in a string.
public static int GetLongestSequenceOfSameCharacters(this string sequence)
{
var data = new List<char>();
for (int i = 0; i < sequence.Length; i++)
{
if (i > 0 && (sequence[i] == sequence[i - 1]))
{
data.Add(sequence[i]);
}
}
return data.GroupBy(x => x).Max(x => x.Count()) + 1;
}
[TestMethod]
public void TestMethod1()
{
// Arrange
string sequence = "aabbbbccccce";
// Act
int containsSameNumbers = sequence.GetLongestSequenceOfSameCharacters();
// Assert
Assert.IsTrue(containsSameNumbers == 5);
}

Categories

Resources