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;
}
Related
public static class Inova
{
public static bool IsPangram(string str)
{
int compteur = 26;
for (int i = 0; i <= str.Length; i++)
{
if (('A' <= str[i] && str[i] <= 'Z') || ('a' <= str[i] && str[i] <= 'z'))
{
for (int j = str[i + 1]; j <= str.Length; j++)
{
if (compteur != 0 && str[i] != str[j])
{
compteur = compteur - 1;
}
}
}
if (compteur == 0)
{
return true;
}
else
{
return false;
}
}
}
}
There are multiple things incorrect:
for (int j = str[i + 1]; j <= str.Length; j++)
this does not do what you think, it will convert the next char to an int, you want to loop all letters until end, beginning from the current letter + 1.
The if ... else belong to the end of the method, outside of the loop, otherwise you return false after the first iteration in the for-loop
So you want to know if it's a perfect pangram? First we need to say what a pangram is: a sentence containing every letter of the alphabet. It seems you want to check if it's even a perfect pangram, so every letter should appear exactly once. Here is a method not using any fancy LINQ(which might not be allowed) that supports perfect/imperfect pangrams:
public static class Inova
{
private const string alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
public static bool IsPangram(string str, bool mustBePerfect)
{
HashSet<char> remaingLetters = new HashSet<char>(alphabet);
foreach (char c in str)
{
char letter = char.ToUpperInvariant(c);
if (!alphabet.Contains(letter)) continue;
bool repeatingLetter = !remaingLetters.Remove(letter);
if (mustBePerfect && repeatingLetter)
{
return false; // already removed
}
}
return remaingLetters.Count == 0;
}
}
Usage:
bool isPangram = Inova.IsPangram("abcdefghijklmnopqrstuvwxyZZ", false);
Since z appears twice this method returns false for perfect and true for not perfect.
Demo: https://dotnetfiddle.net/gEXuvG
Side-note: i wanted to keep it simple, if you want you can still improve it. You can return true in the loop: if(!mustBePerfect && remaingLetters.Count == 0) return true.
I would check for existence of each letter in the string, so
public static bool IsPangram(string str) {
str = str.ToLower();
for (int i = 0; i < 26; i++) {
char c = Convert.ToChar(i + 97);
if (!str.Contains(c)) {
return false;
}
}
return true;
}
Console.WriteLine(IsPangram("hello world"));
Console.WriteLine(IsPangram("abcdefghi jkl mno pqrstuvwxyz"));
// output:
False
True
I'm trying to find a long string in another string. For this I've been using G[i].Contains(P[arr]) but for some reason the code just skips that condition. In my case : G[I] is 1000 character long and P[arr] is 475. When I debug I can see strings are not trimmed and also I have verified that P[ARR] is part of G[I] in Notepad++ so it should definitely satisfy a condition.
for (int arr = 0; arr < P.Length; arr++)
{
for (int i = a; i < G.Length; i++)
{
if (G[i].Contains(P[arr]))
{
if (!(b == 0))
{
a = i + 1;
continue;
}
primary_1 = (a == 0) ? G[i].IndexOf(P[arr]) : primary;
++count;
a = i + 1;
Console.WriteLine("Counter: " + i);
break;
}
}
}
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
There is an error with that string.compiler thingy and i dont know what to do. i really need some help please
char[] valWord = new char[100];
Console.WriteLine(textBox1.Text);
valWord = textBox1.Text;
int beg = 0;
int val = 0;
int value = 0;
for (int i = 0; i < 100; i++)
{
if (valWord[i] == ' ' || valWord[i] == '\0')
{
char[] temp = new char[100];
for (int j = 0; j < i - beg; j++)
{
temp[j] = valWord[beg + j];
}
temp[i - beg] = '\0';
//there is an error in this if statement: String.Compare
if (String.Compare(temp, "thousand") == 0)
{
value += (val*1000);
val = 0;
}
else if (String.Compare(temp, "hundred") == 0)
{
value += (val*100);
val = 0;
}
else if (String.Compare(temp, "one") == 0)
{
val = 1;
}
else if (String.Compare(temp, "two") == 0)
{
val = 2;
}
if (valWord[i] == '\0')
{
value += val;
break;
}
}
Console.WriteLine(textBox2.Text);
}
else
{
_list.Add(name, new GenericList());
}
You can't compare a string to a char array. They are different types.
Use if (string.Equals(new string(temp),"thousand")) instead.
As per MSDN, there is no such function overload defined for String.Compare
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);
}