I need to write a function which verifies parentheses are balanced in a string. Each open parentheses should have a corresponding close parentheses and they should correspond correctly.
For example, the function should return true for the following strings:
(if (any? x) sum (/1 x))
I said (it's not (yet) complete). (she didn't listen)
The function should return false for the following strings:
:-)
())(
OPTIONAL BONUS
Implement the solution as a recursive function with no mutation / side-effects.
Can you please help me out in writing using C# because I'm new to .NET technologies.
Thanks.
Here's what I've tried so far. It works for sending parameters as open and close brackets, but I'm confused with just passing a string... and also I should not use stack.
private static bool Balanced(string input, string openParenthesis, string closedParenthesis)
{
try
{
if (input.Length > 0)
{
//Obtain first character
string firstString = input.Substring(0, 1);
//Check if it is open parenthesis
//If it is open parenthesis push it to stack
//If it is closed parenthesis pop it
if (firstString == openParenthesis)
stack.Push(firstString);
else if (firstString == closedParenthesis)
stack.Pop();
//In next iteration, chop off first string so that it can iterate recursively through rest of the string
input = input.Substring(1, input.Length - 1);
Balanced(input, openParenthesis, closedParenthesis); //this call makes the function recursive
}
if (stack.Count == 0 && !exception)
isBalanced = true;
}
catch (Exception ex)
{
exception = true;
}
return isBalanced;
}
You don't need to use any recursion method for such a simple requirement, just try this simple method and it works like a charm:
public bool AreParenthesesBalanced(string input) {
int k = 0;
for (int i = 0; i < input.Length; i++) {
if (input[i] == '(') k++;
else if (input[i] == ')'){
if(k > 0) k--;
else return false;
}
}
return k == 0;
}
I have used the startIndex and increment with each recursive call
List<string> likeStack = new List<string>();
private static bool Balanced(string input, string openParenthesis, string closedParenthesis , int startIndex)
{
try
{
if (startIndex < input.Length)
{
//Obtain first character
string firstString = input.Substring(startIndex, 1);
//Check if it is open parenthesis
//If it is open parenthesis push it to stack
//If it is closed parenthesis pop it
if (firstString == openParenthesis)
likeStack.Add(firstString);
else if (firstString == closedParenthesis)
likeStack.RemoveAt(likeStack.Count -1);
//In next iteration, chop off first string so that it can iterate recursively through rest of the string
Balanced(input, openParenthesis, closedParenthesis , startIndex + 1); //this call makes the function recursive
}
if (likeStack.Count == 0 && !exception)
isBalanced = true;
}
catch (Exception ex)
{
exception = true;
}
return isBalanced;
}
How's this recursive version?
public static bool Balanced(string s)
{
var ix = -1;
return Balanced(s, false, ref ix);
}
private static bool Balanced(string s, bool inParens, ref int ix)
{
ix++;
while (ix < s.Length)
{
switch (s[ix++])
{
case '(':
if (!Balanced(s, true, ref ix))
return false;
break;
case ')':
return inParens;
}
}
return !inParens;
}
Related
Im trying to write a function complex_decode( string str) in c sharp that takes a non-simple repeated encoded string, and returns the original un-encoded string.
for example, "t11h12e14" would return "ttttttttttthhhhhhhhhhhheeeeeeeeeeeeee". I have been successful in decoding strings where the length is less than 10, but unable to work with length for than 10. I am not allowed to use regex, libraries or loops. Only recursions.
This is my code for simple decode which decodes when length less than 10.
public string decode(string str)
{
if (str.Length < 1)
return "";
if(str.Length==2)
return repeat_char(str[0], char_to_int(str[1]));
else
return repeat_char(str[0], char_to_int(str[1]))+decode(str.Substring(2));
}
public int char_to_int(char c)
{
return (int)(c-48);
}
public string repeat_char(char c, int n)
{
if (n < 1)
return "";
if (n == 1)
return ""+c;
else
return c + repeat_char(c, n - 1);
}
This works as intended, for example input "a5" returns "aaaaa", "t1h1e1" returns "the"
Any help is appreciated.
Here is another way of doing this, assuming the repeating string is always one character long and using only recursion (and a StringBuilder object):
private static string decode(string value)
{
var position = 0;
var result = decode_char(value, ref position);
return result;
}
private static string decode_char(string value, ref int position)
{
var next = value[position++];
var countBuilder = new StringBuilder();
get_number(value, ref position, countBuilder);
var result = new string(next, Convert.ToInt32(countBuilder.ToString()));
if (position < value.Length)
result += decode_char(value, ref position);
return result;
}
private static void get_number(string value, ref int position, StringBuilder countBuilder)
{
if (position < value.Length && char.IsNumber(value[position]))
{
countBuilder.Append(value[position++]);
get_number(value, ref position, countBuilder);
}
}
I've refactored your code a bit. I've removed 2 unnecessary methods that you don't actually need. So, the logic is simple and it works like this;
Example input: t3h2e4
Get the first digit. (Which is 2 and has index of 1)
Get the first letter comes after that index, which is our next letter. (Which is "h" and has index of 2)
Slice the string. Start from index 1 and end the slicing on index 2 to get repeat count. (Which is 3)
Repeat the first letter of string for repeat count times and combine it with the result you got from step 5.
Slice the starting from the next letter index we got in second step, to the very end of the string and pass this to recursive method.
public static string Decode(string input)
{
// If the string is empty or has only 1 character, return the string itself to not proceed.
if (input.Length <= 1)
{
return input;
}
// Convert string into character list.
var characters = new List<char>();
characters.AddRange(input);
var firstDigitIndex = characters.FindIndex(c => char.IsDigit(c)); // Get first digit
var nextLetterIndex = characters.FindIndex(firstDigitIndex, c => char.IsLetter(c)); // Get the next letter after that digit
if (nextLetterIndex == -1)
{
// This has only one reason. Let's say you are in the last recursion and you have c2
// There is no letter after the digit, so the index will -1, which means "not found"
// So, it will raise an exception, since we try to use the -1 in slicing part
// Instead, if it's not found, we set the next letter index to length of the string
// With doing that, you either get repeatCount correctly (since remaining part is only digits)
// or you will get empty string in the next recursion, which will stop the recursion.
nextLetterIndex = input.Length;
}
// Let's say first digit's index is 1 and the next letter's index is 2
// str[2..3] will start to slice the string from index 2 and will stop in index 3
// So, it will basically return us the repeat count.
var repeatCount = int.Parse(input[firstDigitIndex..nextLetterIndex]);
// string(character, repeatCount) constructor will repeat the "character" you passed to it for "repeatCount" times
return new string(input[0], repeatCount) + Decode(input[nextLetterIndex..]);
}
Examples;
Console.WriteLine(Decode("t1h1e1")); // the
Console.WriteLine(Decode("t2h3e4")); // tthhheeee
Console.WriteLine(Decode("t3h3e3")); // ttthhheee
Console.WriteLine(Decode("t2h10e2")); // tthhhhhhhhhhee
Console.WriteLine(Decode("t2h10e10")); // tthhhhhhhhhheeeeeeeeee
First you can simplify your repeat_char function, you have to have a clear stop condition:
public static string repeat_char(char c, int resultLength)
{
if(resultLength < 1) throw new ArgumentOutOfRangeException("resultLength");
if(resultLength == 1) return c.ToString();
return c + repeat_char(c, resultLength - 1);
}
See the use of the parameter as equivalent of a counter on a loop.
So you can have something similar on the main function, a parameter that tells when your substring is not an int anymore.
public static string decode(string str, int repeatNumberLength = 1)
{
if(repeatNumberLength < 1) throw new ArgumentOutOfRangeException("length");
//stop condition
if(string.IsNullOrWhiteSpace(str)) return str;
if(repeatNumberLength >= str.Length) repeatNumberLength = str.Length; //Some validation, just to be safe
//keep going until str[1...repeatNumberLength] is not an int
int charLength;
if(repeatNumberLength < str.Length && int.TryParse(str.Substring(1, repeatNumberLength), out charLength))
{
return decode(str, repeatNumberLength + 1);
}
repeatNumberLength--;
//Get the repeated Char.
charLength = int.Parse(str.Substring(1, repeatNumberLength));
var repeatedChar = repeat_char(str[0], charLength);
//decode the substring
var decodedSubstring = decode(str.Substring(repeatNumberLength + 1));
return repeatedChar + decodedSubstring;
}
I used a default parameter, but you can easily change it for a more traditonal style.
This also assumes that the original str is in a correct format.
An excellent exercise is to change the function so that you can have a word, instead of a char before the number. Then you could, for example, have "the3" as the parameter (resulting in "thethethe").
I took more of a Lisp-style head and tail approach (car and cdr if you speak Lisp) and created a State class to carry around the current state of the parsing.
First the State class:
internal class State
{
public State()
{
LastLetter = string.Empty;
CurrentCount = 0;
HasStarted = false;
CurrentValue = string.Empty;
}
public string LastLetter { get; private set; }
public int CurrentCount { get; private set; }
public bool HasStarted { get; private set; }
public string CurrentValue { get; private set; }
public override string ToString()
{
return $"LastLetter: {LastLetter}, CurrentCount: {CurrentCount}, HasStarted: {HasStarted}, CurrentValue: {CurrentValue}";
}
public void AddLetter(string letter)
{
CurrentCount = 0;
LastLetter = letter;
HasStarted = true;
}
public int AddDigit(string digit)
{
if (!HasStarted)
{
throw new InvalidOperationException($"The input must start with a letter, not a digit");
}
if (!int.TryParse(digit, out var num))
{
throw new InvalidOperationException($"Digit passed to {nameof(AddDigit)} ({digit}) is not a number");
}
CurrentCount = CurrentCount * 10 + num;
return CurrentCount;
}
public string GetValue()
{
if (string.IsNullOrEmpty(LastLetter))
{
return string.Empty;
}
CurrentValue = new string(LastLetter[0], CurrentCount);
return CurrentValue;
}
}
You'll notice it's got some stuff in there for debugging (example, the ToString override and the CurrentValue property)
Once you have that, the decoder is easy, it just recurses over the string it's given (along with (initially) a freshly constructed State instance):
private string Decode(string input, State state)
{
if (input.Length == 0)
{
_buffer.Append(state.GetValue());
return _buffer.ToString();
}
var head = input[0];
var tail = input.Substring(1);
var headString = head.ToString();
if (char.IsDigit(head))
{
state.AddDigit(headString);
}
else // it's a character
{
_buffer.Append(state.GetValue());
state.AddLetter(headString);
}
Decode(tail, state);
return _buffer.ToString();
}
I did this in a simple Windows Forms app, with a text box for input, a label for output and a button to crank her up:
const string NotAllowedPattern = #"[^a-zA-Z0-9]";
private static Regex NotAllowedRegex = new Regex(NotAllowedPattern);
private StringBuilder _buffer = new StringBuilder();
private void button1_Click(object sender, EventArgs e)
{
if (textBox1.Text.Length == 0 || NotAllowedRegex.IsMatch(textBox1.Text))
{
MessageBox.Show(this, "Only Letters and Digits Allowed", "Bad Input", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
label1.Text = string.Empty;
_buffer.Clear();
var result = Decode(textBox1.Text, new State());
label1.Text = result;
}
Yeah, there's a Regex there, but it's just to make sure that the input is valid; it's not involved in calculating the output.
I've made my own way to check if the amount of () and "" are equal. So for example "H(ell)o") is correct. However, the problem I face is that what if the first bracket is ) and the other is ( example "H)ell(o" this would mean it's incorrect. So my question is how would I check whether the first bracket in any word is opening?
EDIT:
public static Boolean ArTinkaSintakse(char[] simboliai)
{
int openingBracketsAmount = 0;
int closingBracketsAmount = 0;
int quotationMarkAmount = 0;
for (int i = 0; i < simboliai.Length; i++)
{
if (openingBracketsAmount == 0 && simboliai[i] == ')')
break;
else if (simboliai[i] == '\"')
quotationMarkAmount++;
else if (simboliai[i] == '(')
openingBracketsAmount++;
else if (simboliai[i] == ')')
closingBracketsAmount++;
}
int bracketAmount = openingBracketsAmount + closingBracketsAmount;
if (quotationMarkAmount % 2 == 0 && bracketAmount % 2 == 0)
return true;
else
return false;
}
Add a check for if (openingBracketsAmount < closingBracketsAmount). If that's ever true, you know that the brackets are unbalanced.
Add an if statement that breaks out of the loop if the first bracket encountered is a closing bracket, like so:
for (int i = 0; i < word.Length; i++)
{
if ((openingBracketsAmount == 0) && (word[i] == ')'))
{
<Log error...>
break;
}
<Rest of your loop...>
}
This way, as soon as openingBracketsAmount is updated, this if statement will be unreachable.
I would approach the problem recursively.
Create a Dictionary<char, char> to keep track of which opening character goes with which closing one.
Then I would implement:
boolean findMatches(string input, out int lastIndex) {}
The method will scan until a member of the Dictionary keys is found. Then it will recursively call itself with the remainder of the string. If the recursive call comes back false, return that. If true, check if the lastIndex character (or the one after; I always need to write the code to check fenceposts) is the matching bracket you want. If it is, and you're not at the end of the string, return the value of a recursive call with the rest of the string after that matching bracket. If you are at the end, return true with that character's index. If that character isn't the matching bracket/quote, pass the remainder of the string (including that last character) to another recursive call.
Continue until you reach the end of the string (returning true if you aren't matching a bracket or quote, false otherwise). Either way with a lastIndex of the last character.
Probably you need a stack-based approach to validate such expressions.
Please try the following code:
public static bool IsValid(string s)
{
var pairs = new List<Tuple<char, char>>
{
new Tuple<char, char>('(', ')'),
new Tuple<char, char>('{', '}'),
new Tuple<char, char>('[', ']'),
};
var openTags = new HashSet<char>();
var closeTags = new Dictionary<char, char>(pairs.Count);
foreach (var p in pairs)
{
openTags.Add(p.Item1);
closeTags.Add(p.Item2, p.Item1);
}
// Remove quoted parts
Regex r = new Regex("\".*?\"", RegexOptions.Compiled | RegexOptions.Multiline);
s = r.Replace(s, string.Empty);
var opened = new Stack<char>();
foreach (var ch in s)
{
if (ch == '"')
{
// Unpaired quote char
return false;
}
if (openTags.Contains(ch))
{
// This is a legal open tag
opened.Push(ch);
}
else if (closeTags.TryGetValue(ch, out var openTag) && openTag != opened.Pop())
{
// This is an illegal close tag or an unbalanced legal close tag
return false;
}
}
return true;
}
I am trying to write a function to control if the parenthesis included in a stringare balanced or not.
I have written the following function:
public bool IsBalanced(string input)
{
//last condition, gets out
if (string.IsNullOrEmpty(input)) return true;
int numOpen = 0;
bool opened = false;
foreach (char c in input)
{
if (char.ToUpperInvariant(c) =='(')
{
opened = true;
numOpen+=1;
}
if (char.ToUpperInvariant(c) == ')')
{
if (opened)
{
numOpen-=1;
opened = numOpen > 0;
}
else
return false; //incorrect position parentheses, closes but not opened
}
}
return numOpen == 0;
}
I wanted to change it to a recursive function, but have not been able to do so. Could anyone give a hint how to do it?
Well, your algorithm is not pretty. Here is a better one
int check = 0;
foreach (var c in input)
{
if (c == '(') {
check++;
} else if (c == ')') {
check--;
}
if (check < 0) {
return false; // error, closing bracket without opening brackets first
}
}
return check == 0; // > 0 error, missing some closing brackets
To make it (algorithm of checking for balanced brackets) recursive you can go with following
bool IsBalanced(string input)
{
var first = input.IndexOf('('); // first opening bracket position
var last = input.LastIndexOf(')'); // last closing bracket position
if (first == -1 && last == -1)
return true; // no more brackets - balanced
if (first == -1 && last != -1 || first != -1 && last == -1)
return false; // error - one of brackets is missing
if (first > last)
return false; // error - closing bracket is BEFORE opening
return IsBalanced(input.Substring(first, last - first)); // not sure, might need to tweak it, parameter should be without first and last bracket (what is inside)
}
This simply remove first opening brackets and last closing bracket and pass what is left as parameter (recursively) until one of the end conditions is met.
The basic idea is to take a variant (numOpen in this case) as an argument.
Here is my code:
public bool IsBalancedRec(string input, int numOpen = 0)
{
if (numOpen < 0)
return false;
if (string.IsNullOrEmpty(input))
return numOpen == 0;
char c = input[0];
string rest = input.Substring(1);
if (c == '(')
return IsBalancedRec(rest, numOpen + 1);
else if (c == ')')
return IsBalancedRec(rest, numOpen - 1);
else
return IsBalancedRec(rest, numOpen);
}
And call this like IsBalancedRec("so(m(eth)ing)").
Implement with stack:
Stack myStak = new Stack();
public bool IsBalanced(string input)
{
if (input.ToArray().Count() != 0)
{
if(input.ToArray()[0] == '(')
{
myStak.Push('(');
}
else if(input.ToArray()[0] == ')')
{
if (myStak.Count != 0)
myStak.Pop();
else
{
//not balanced
return false;
}
}
return IsBalanced(input.Substring(1));
}
else
{
if (myStak.Count == 0)
{
//balanced
return true;
}
else
{
//not balanced
return false;
}
}
}
public static bool IsBalanced(string input)
{
int numOpen = 0;
while(input != "")
{
char c = input[0];
input = input.Substring(1);
numOpen = c == '(' ? (numOpen + 1) : (c == ')' ? (numOpen - 1) : numOpen);
}
return numOpen == 0;
}
// count no of left and right bracket or parenthesis and check counts
var InputStr= str.ToCharArray();
int left = 0;
int right = 0;
foreach (char item in InputStr)
{
if(item == '(')
{
left ++;
} else if(item == ')')
{
right ++;
}
}
if(right == l)
{
return "1";
}
return "0";
}
EDIT
Apologies if the original unedited question is misleading.
This question is not asking how to remove Invalid XML Chars from a string, answers to that question would be better directed here.
I'm not asking you to review my code.
What I'm looking for in answers is, a function with the signature
string <YourName>(string input, Func<char, bool> check);
that will have performance similar or better than RemoveCharsBufferCopyBlackList. Ideally this function would be more generic and if possible simpler to read, but these requirements are secondary.
I recently wrote a function to strip invalid XML chars from a string. In my application the strings can be modestly long and the invalid chars occur rarely. This excerise got me thinking. What ways can this be done in safe managed c# and, which would offer the best performance for my scenario.
Here is my test program, I've subtituted the "valid XML predicate" for one the omits the char 'X'.
class Program
{
static void Main()
{
var attempts = new List<Func<string, Func<char, bool>, string>>
{
RemoveCharsLinqWhiteList,
RemoveCharsFindAllWhiteList,
RemoveCharsBufferCopyBlackList
}
const string GoodString = "1234567890abcdefgabcedefg";
const string BadString = "1234567890abcdefgXabcedefg";
const int Iterations = 100000;
var timer = new StopWatch();
var testSet = new List<string>(Iterations);
for (var i = 0; i < Iterations; i++)
{
if (i % 1000 == 0)
{
testSet.Add(BadString);
}
else
{
testSet.Add(GoodString);
}
}
foreach (var attempt in attempts)
{
//Check function works and JIT
if (attempt.Invoke(BadString, IsNotUpperX) != GoodString)
{
throw new ApplicationException("Broken Function");
}
if (attempt.Invoke(GoodString, IsNotUpperX) != GoodString)
{
throw new ApplicationException("Broken Function");
}
timer.Reset();
timer.Start();
foreach (var t in testSet)
{
attempt.Invoke(t, IsNotUpperX);
}
timer.Stop();
Console.WriteLine(
"{0} iterations of function \"{1}\" performed in {2}ms",
Iterations,
attempt.Method,
timer.ElapsedMilliseconds);
Console.WriteLine();
}
Console.Readkey();
}
private static bool IsNotUpperX(char value)
{
return value != 'X';
}
private static string RemoveCharsLinqWhiteList(string input,
Func<char, bool> check);
{
return new string(input.Where(check).ToArray());
}
private static string RemoveCharsFindAllWhiteList(string input,
Func<char, bool> check);
{
return new string(Array.FindAll(input.ToCharArray(), check.Invoke));
}
private static string RemoveCharsBufferCopyBlackList(string input,
Func<char, bool> check);
{
char[] inputArray = null;
char[] outputBuffer = null;
var blackCount = 0;
var lastb = -1;
var whitePos = 0;
for (var b = 0; b , input.Length; b++)
{
if (!check.invoke(input[b]))
{
var whites = b - lastb - 1;
if (whites > 0)
{
if (outputBuffer == null)
{
outputBuffer = new char[input.Length - blackCount];
}
if (inputArray == null)
{
inputArray = input.ToCharArray();
}
Buffer.BlockCopy(
inputArray,
(lastb + 1) * 2,
outputBuffer,
whitePos * 2,
whites * 2);
whitePos += whites;
}
lastb = b;
blackCount++;
}
}
if (blackCount == 0)
{
return input;
}
var remaining = inputArray.Length - 1 - lastb;
if (remaining > 0)
{
Buffer.BlockCopy(
inputArray,
(lastb + 1) * 2,
outputBuffer,
whitePos * 2,
remaining * 2);
}
return new string(outputBuffer, 0, inputArray.Length - blackCount);
}
}
If you run the attempts you'll note that the performance improves as the functions get more specialised. Is there a faster and more generic way to perform this operation? Or if there is no generic option is there a way that is just faster?
Please note that I am not actually interested in removing 'X' and in practice the predicate is more complicated.
You certainly don't want to use LINQ to Objects aka enumerators to do this if you require high performance. Also, don't invoke a delegate per char. Delegate invocations are costly compared to the actual operation you are doing.
RemoveCharsBufferCopyBlackList looks good (except for the delegate call per character).
I recommend that you inline the contents of the delegate hard-coded. Play around with different ways to write the condition. You may get better performance by first checking the current char against a range of known good chars (e.g. 0x20-0xFF) and if it matches let it through. This test will pass almost always so you can save the expensive checks against individual characters which are invalid in XML.
Edit: I just remembered I solved this problem a while ago:
static readonly string invalidXmlChars =
Enumerable.Range(0, 0x20)
.Where(i => !(i == '\u000A' || i == '\u000D' || i == '\u0009'))
.Select(i => (char)i)
.ConcatToString()
+ "\uFFFE\uFFFF";
public static string RemoveInvalidXmlChars(string str)
{
return RemoveInvalidXmlChars(str, false);
}
internal static string RemoveInvalidXmlChars(string str, bool forceRemoveSurrogates)
{
if (str == null) throw new ArgumentNullException("str");
if (!ContainsInvalidXmlChars(str, forceRemoveSurrogates))
return str;
str = str.RemoveCharset(invalidXmlChars);
if (forceRemoveSurrogates)
{
for (int i = 0; i < str.Length; i++)
{
if (IsSurrogate(str[i]))
{
str = str.Where(c => !IsSurrogate(c)).ConcatToString();
break;
}
}
}
return str;
}
static bool IsSurrogate(char c)
{
return c >= 0xD800 && c < 0xE000;
}
internal static bool ContainsInvalidXmlChars(string str)
{
return ContainsInvalidXmlChars(str, false);
}
public static bool ContainsInvalidXmlChars(string str, bool forceRemoveSurrogates)
{
if (str == null) throw new ArgumentNullException("str");
for (int i = 0; i < str.Length; i++)
{
if (str[i] < 0x20 && !(str[i] == '\u000A' || str[i] == '\u000D' || str[i] == '\u0009'))
return true;
if (str[i] >= 0xD800)
{
if (forceRemoveSurrogates && str[i] < 0xE000)
return true;
if ((str[i] == '\uFFFE' || str[i] == '\uFFFF'))
return true;
}
}
return false;
}
Notice, that RemoveInvalidXmlChars first invokes ContainsInvalidXmlChars to save the string allocation. Most strings do not contain invalid XML chars so we can be optimistic.
my program should print a message on the screen if the formula that the user entered is good for the terms(you can only use digits and letters, u can't start with '(' and like mathematical formula, for each open bracket, has to be a suitable(and in the right place) close bracket.
here some formulas that the program should accepts and prints:
True-
a(aa(a)aaa(aa(a)aa)aa)aaaaa
a(((())))
here some formulas that the program should not accepts and prints:
False-
()()()
)()()(
but the program always prints False
thanks for helping
Heres the code:EDIT
bool IsNumeric(char character)
{
return "0123456789".Contains(character);
// or return Char.IsNumber(character);
}
bool IsLetter(char character)
{
return "ABCDEFGHIJKLMNOPQRSTUVWXWZabcdefghigjklmnopqrstuvwxyz".Contains(character);
}
bool IsRecognized(char character)
{
return IsBracket(character) | IsNumeric(character) | IsLetter(character);
}
public bool IsValidInput(string input)
{
if (String.IsNullOrEmpty(input) || IsBracket(input[0]))
{
return false;
}
var bracketsCounter = 0;
for (var i = 0; i < input.Length; i++)
{
var character = input[i];
if (!IsRecognized(character))
{
return false;
}
if (IsBracket(character))
{
if (character == '(')
bracketsCounter++;
if (character == ')')
bracketsCounter--;
}
}
if (bracketsCounter > 0)
{
return false;
}
return bracketsCounter==0;
}
}
}
Your algorithm is unnecessarily complex - all you need is a loop and a counter.
Check the initial character for ( (you already do that)
Set the counter to zero, and go through each character one by one
If the character is not a letter or a parentheses, return false
If the character is an opening (, increment the counter
If the character is a closing ), decrement the counter; if the counter is less than zero, return false
Return true if the count is zero after the loop has ended; otherwise return false
Is debugging this hard really? This condition:
((!IsNumeric(st[i])) && (st[i] != '(') && (st[i] != ')')&&((st[i]<'a')||(st[i]>'z')||(st[i]<'A')||(st[i]>'Z')))
return false;
is obviously wrong. It returns false for a every time. You don't take into consideration that a is greater than Z.
EDIT:
so how can i make it easier to read? that the only way i figured. do u
have other solution for this problem?
As for that condition block - use smaller methods / functions, for example.
bool IsBracket(char character)
{
return (character == '(' | character == ')');
}
bool IsNumeric(char character)
{
return "0123456789".Contains(character);
// or return Char.IsNumber(character);
}
bool IsLetter(char character)
{
// see why this is NOT prone to fail just because 'a' is greater than 'Z' in C#?
return (character >= 'a' & character <= 'z') |
(character >= 'A' & character <= 'Z');
// or return Regex.IsMatch(character.ToString(), "[a-zA-Z]", RegexOptions.None);
// or return Char.IsLetter(character);
}
// now you can implement:
bool IsRecognized(char character)
{
return IsBracket(character) | IsNumeric(character) | IsLetter(character);
}
and then in your big method you could just safely use:
if (!IsRecognized(st[i]))
return false;
It may look like an overkill for such a trivial example, but it's a better approach in principle, and certainly more readable.
And after that, you could reduce your code to something along the lines of:
bool IsInputValid(string input)
{
if (String.IsNullOrEmpty(input) || IsBracket(input[0]))
{
return false;
}
var bracketsCounter = 0;
for (var i = 0; i < input.Length; i++)
{
var character = input[i];
if (!IsRecognized(character))
{
return false;
}
if (IsBracket(character)) // redundant?
{
if (character == '(') // then what?
if (character == ')') // then what?
}
if (bracketsCounter < what?)
{
what?
}
}
return bracketsCounter == what?;
}
(dasblinkenlight's algorithm)
EDIT 10th April
You got it wrong.
bool IsNumeric(char character)
{
return "0123456789".Contains(character);
// or return Char.IsNumber(character);
}
bool IsLetter(char character)
{
return "ABCDEFGHIJKLMNOPQRSTUVWXWZabcdefghigjklmnopqrstuvwxyz".Contains(character);
}
bool IsRecognized(char character)
{
return IsBracket(character) | IsNumeric(character) | IsLetter(character);
}
public bool IsValidInput(string input)
{
if (String.IsNullOrEmpty(input) || IsBracket(input[0]))
{
return false;
}
var bracketsCounter = 0;
for (var i = 0; i < input.Length; i++)
{
var character = input[i];
if (!IsRecognized(character))
{
return false;
}
if (IsBracket(character))
{
if (character == '(')
bracketsCounter++;
if (character == ')')
bracketsCounter--;
}
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
if (bracketsCounter < 0) // NOT "> 0", and HERE - INSIDE the for loop
{
return false;
}
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
}
return bracketsCounter==0;
}
}
}
By the way, you also made a mistake in your IsLetter method:
...UVWXWZ? Should be UVWXYZ