C#, check string if 'a letter' is followed by 'a letter' - c#

Let say, * has to be followed by &.
For example,
string asd = "Mother*&Mother*&Son";
// which is "Mother+ "*&" + "Mother" + "*&" + "Son"
// This is correct string.
Bad example,
string asd = "Mother*Mother*&Son";
string asf = "Mother**&Mother*&Son";
string asg = "Mother*&*Mother*&Son";
How can I check if the string is correct or not in C#?
EDIT
based on the usage of Regex that you guys introduced, I have a side question. I am actually using comma(,) instead of asterisk(*) and quotation mark(") instead of ampersand(&).
In C#, (Let me use one of the guy's example)
Regex.IsMatch("Mother,\",Mother,\"Son", #"\,(?!")")
//won't work.. any idea?
I also tried
Regex.IsMatch("Mother,\",Mother,\"Son", #"\,(?!\")")
//not work, neither

Find failures by looking for any asterisk (*) not followed by an ampersand (&):
Regex.IsMatch("Mother*&*Mother*&Son", #"\*(?!&)")

You can use regex. But it will be easier to find when string is not correct and then just negate the result.
I would look for any * which is not followed by &. The regex should look like: (\*[^&])|(\*$)
Simple test code:
var inputs = new[] {
"Mother*&Mother*&Son",
"Mother*Mother*&Son",
"Mother**&Mother*&Son",
"Mother*&*Mother*&Son",
"Mother*&Mother*&Son*"
};
var regex = new Regex(#"(\*[^&])|(\*$)");
var isOK = inputs.Select(x => !regex.IsMatch(x)).ToList();
Returns a list of results, which contains true, false, false, false, false.

For something like this, I'd favor the direct approach, rather than using Regex. This will make at most one pass through the entire string, which should be more efficient than a Regex.
/// Return true if every instance of 'a' in the string is followed by 'b'.
/// Also returns true if there are no instances of 'a' in the string.
/// Returns false if there exists any 'a' that is not followed by 'b'.
public static bool IsTwoCharSequence(string s, char a, char b)
{
if(String.IsNullOrEmpty(s)) return true;
if(s[s.Length - 1] == a) return false; // ends in a, not followed by b. Condition failed.
int index = s.IndexOf(a); // find the first a
while(index != -1)
{
if(s[index + 1] != b) return false; // a not followed by b.
index = s.IndexOf(a, index + 1);
}
return true; // either no a, or all a followed by b.
}
Edit: In addition, you don't need to worry about how to quote your separator characters, when they're also special characters within a Regex.
Edit 2: Yes, it's two loops, but look at what each loop is doing.
The inner loop, the one inside of String.IndexOf, will iterate through characters until it finds the passed-in character. The first call to IndexOf (the one outside the while loop) starts searching at the beginning of the string, and the subsequent ones start at that index, and continue searching to the next match, or to the end. Overall, we've made just one pass over the entire string.
Here's another method, which is similar in concept to the above one, but where the 'iterate the entire string only once' is more explicit.
public static bool IsTwoCharSequence(string s, char a, char b)
{
if (String.IsNullOrEmpty(s)) return true;
bool foundA = false;
foreach (char c in s)
{
if (foundA && c == b)
foundA = false;
else if (foundA)
return false;
else if (c == a)
foundA = true;
}
if (foundA) return false; // 'a' was the last char in the string.
return true;
}

Use Regular expressions and check that the number of matches for *& is the same as the number of *s
code of the top of my head, may not compile but try:
Regex r = new Regex(#"\*&");
Regex r2 = new Regex(#"\*");
if (r.Matches(myString).Count == r2.Matches(myString).Count) //success!

Related

How to compare whether two strings are identical?

So I'm doing this years Advent of Code and I'm stuck on the second day, part 2.
You are given inputs which look like this:
"1-3 c: caaasa"
You have to check how many passwords are valid due to the policy like,
in above example:
letter c has to be in position 1 OR 3 in the string caaasa. If
yes, the password is valid.
I've broken down that string to different sections, and now I try to compare a string "znak" which contains that given letter to a letter on position zakresmin and zakresmax in string "passdiv"
Yet, everytime it returns False, so it doesn't add up to the count of passwords.
I tried using Equals() and CompareTo(), but they don't seem to work.
How can I modify my code so it returns proper values?
var iloschasel = 0;
using (StreamReader sr = new StreamReader(#"C:\Users\Wurf\Desktop\text.txt"))
{
string line;
while ((line = sr.ReadLine()) != null)
{
string[] linia = line.Split(" ");
string zakres = linia[0];
string[] zakresy = zakres.Split("-");
int zakresmin = Convert.ToInt32(zakresy[0]);
int zakresmax = Convert.ToInt32(zakresy[1]);
string znak = (linia[1].Replace(":", "")).Trim();
var suma = Regex.Matches(linia[2], znak);
string passdiv = linia[2];
if(passdiv[zakresmin].Equals(znak) || passdiv[zakresmax - 1].Equals(znak))
{
iloschasel += 1;
}
}
}
Console.WriteLine(iloschasel);
As mentioned, when you call Equals on two different types you are playing a game of chance with how the actual types are implemented. In this case you lose. Strings and chars will never have an equivalence or the same reference.
I believe the compiler or resharper would give you a warning alerting you that neither type derive from string and char
However, I was bored enough to give an alternate solution
public static bool IsValid(string input)
{
var match = Regex.Match(input, #"(\d)-(\d) (\S): (.*)");
if(!match.Success)
throw new ArgumentException( $"Invalid format : {input}",nameof(input));
var first = int.Parse(match.Groups[1].Value);
var second = int.Parse(match.Groups[2].Value);
var c = char.Parse(match.Groups[3].Value);
var password = match.Groups[4].Value;
return password[first-1] == c && password[second-1] == c;
}
Test
Console.WriteLine($"Is Valid = {IsValid("1-3 c: caaasa")}");
Console.WriteLine($"Is Valid = {IsValid("1-3 c: cacaasa")}");
Output
Is Valid = False
Is Valid = True
Note : this is not meant to be a complete bullet-proof solution. Just a novel elegant way to solve your problem
Your problem is that you are comparing a string to a char
var match = "c" == 'c';
Will give a compile error because they are different data types
var match = "c".Equals('c');
will let you compile, but will always return false because a char will never equal a string. You have to turn the char into a string or visa versa for the check to work
var match = "c"[0] == 'c';
So in your if statement, if you fix the check to compare strings with strings or chars with chars you should get some positive results. And also fix your indexing issue to decide if you want a 0 based index or a 1 based index with zakresmin and max
Also as a side note, it can be helpful to step through your code line by line in debug mode, to find out which line isn't behaving like you expect it to. In your case debugging would have helped you zero in on the if statement as a starting point to fixing things.
So it turns out (if I understand that correctly) that a compared element of the string passdiv was a char which I tried to compare to znak which was a string. I added ToString() to my code and it works well. Also fixed the range of zakresmin by subtracting 1 so it works properly.
if((passdiv[zakresmin - 1].ToString() == znak && passdiv[zakresmax - 1].ToString() != znak) || (passdiv[zakresmin - 1].ToString() != znak && passdiv[zakresmax - 1].ToString() == znak))
{
iloschasel += 1;
}

how to check the if condition with string and integer

I want to get result of a value with if condition.
i have get some value in xml file.
now what I want is
if I have a variable "a" here i have assigned some values by using dataset.
and i have another variable "b" is assigned value from xml file.
for example
int a=25;
string b=">10"
now I want to check the condition if condition with out ">" because the symbol present in b variable. I dont know how to check this condition can anybody explain me how to acheive this.
I tried like this but not working
if(a+b)
You can use the DataTable.Compute-"trick" to evaulate such expressions:
int a = 25;
string b = ">10";
bool isTrue = (bool)new DataTable().Compute($"{a}{b}", null); // true
What is supported you can read at the DataColumn.Expression remarks.
if the condition is 1!=10, how to use not equal in this code .this
condition is not working what should i do.
As the documentation tells you that is not valid syntax, you have to use <> (look at operators). So a simple approach would be either to use <> in the first place or replace them:
b = b.Replace("!=", "<>");
You can have some function to remove non numeric characters:
public int Parse(string x)
{
x = Regex.Replace(x, "[^0-9.]", "");
int result = 0;
int.TryParse(x , out result);
return result;
}
If its always a number with a symbol then:
symbol = b[0];
int bval = int.Parse(b.Substring(1))
And considering your comment for comparison you can do:
if((symbol=='>'&&a>b)||
(symbol=='='&&a==b)||
(symbol=='<'&&a<b)
){
//do your magic here
}
Of course you may need only one of < = > or you may need to have separate if conditions for each, what ever suits your needs, but I just wanted to give the idea.
I tried like this
if (b.Contains(">")) {
b = b.Replace(">", "");
if (a >Convert.ToInt32(b))
{
Console.WriteLine("value is less");
}
else
{
Console.WriteLine("value is Greater");
}
}
similarly all the symbols
First separate symbol from b:
string symbol = b[0].ToString();
string numberString = b.SubString(1);
int number = int.Parse(numberString);
Now use switch to get operation for symbol and compare:
bool result = false;
switch (symbol)
{
case ">":
if (a > number)
{
result = true;
}
break;
}
EDIT: Changed symbol declaration to avoid error: "cannot implicit convert type char to string"

How to find a pair of chars within a string in c# netMF?

This has probably (somewhere) been asked before, but can't find any documentation on it (i have looked!).
Say I had declared a string like:
String Test = "abcdefg";
How would i go about searching the string to see if I could see "cd" anywhere in the string by searching through the string in pairs, like:
{ab}{bc}{cd}{de}{ef}{fg}
That is, if I split each of the values up, and searched for a pair of chars next to each other? Is there a built in function for this?
I have thought about using a char array for this, but it seems to (logically) be very 'heavy'/'slow'. Would there be a better solution to search this string?
EDIT 1
Once I see this "cd", I would then need to doSomething() at that position (which I have already implemented by using the substring method.
Try this.
String.IndexOf(...) != -1
For more infö, read here.
Similar to the answer from Neo, but in a loop to get all instances within the string:
string Test = "abcdefgcd";
int index = Test.IndexOf("cd");
while (index > -1)
{
//DoSomething();
index = Test.IndexOf("cd", ++index);
}
The first IndexOf checks for the existence of what you want, whilst the second IndexOf (in the loop) checks for a match after the last index.
In the above we find two matches and then the loop ends.
There is no build in function that will do that.
having a for loop should do what you want.
something like that:
string str = string.empty;
for (i=0;i<ch.length;i++) {
if (i != ch.length) {
str += ch[i] + ch[i+1];
}
}
also you can use regex however that wont be fast either.
In order to optimize this on a large scale you can implement byte shifting.
The ASCII code of your string characters is your friend in this case, full working example below:
var yourString = "abcdefg";
var x = '\0';
for (var i = 0; i < yourString.Length; i++)
{
//check whether i+1 index is not out of range
if (i + 1 != yourString.Length)
{
var test = yourString[i + 1];
x = yourString[i];
if(x.ToString() + test.ToString() == "cd")
{
Console.Write("Found at position " + i)
}
}
}

How to identify if a string contains more than one instance of a specific character?

I want to check if a string contains more than one character in the string?
If i have a string 12121.23.2 so i want to check if it contains more than one . in the string.
You can compare IndexOf to LastIndexOf to check if there is more than one specific character in a string without explicit counting:
var s = "12121.23.2";
var ch = '.';
if (s.IndexOf(ch) != s.LastIndexOf(ch)) {
...
}
You can easily count the number of occurences of a character with LINQ:
string foo = "12121.23.2";
foo.Count(c => c == '.');
If performance matters, write it yourself:
public static bool ContainsDuplicateCharacter(this string s, char c)
{
bool seenFirst = false;
for (int i = 0; i < s.Length; i++)
{
if (s[i] != c)
continue;
if (seenFirst)
return true;
seenFirst = true;
}
return false;
}
In this way, you only make one pass through the string's contents, and you bail out as early as possible. In the worst case you visit all characters only once. In #dasblinkenlight's answer, you would visit all characters twice, and in #mensi's answer, you have to count all instances, even though once you have two you can stop the calculation. Further, using the Count extension method involves using an Enumerable<char> which will run more slowly than directly accessing the characters at specific indices.
Then you may write:
string s = "12121.23.2";
Debug.Assert(s.ContainsDuplicateCharacter('.'));
Debug.Assert(s.ContainsDuplicateCharacter('1'));
Debug.Assert(s.ContainsDuplicateCharacter('2'));
Debug.Assert(!s.ContainsDuplicateCharacter('3'));
Debug.Assert(!s.ContainsDuplicateCharacter('Z'));
I also think it's nicer to have a function that explains exactly what you're trying to achieve. You could wrap any of the other answers in such a function too, however.
Boolean MoreThanOne(String str, Char c)
{
return str.Count(x => x==c) > 1;
}

Has anyone implemented a Regex and/or Xml parser around StringBuilders or Streams?

I'm building a stress-testing client that hammers servers and analyzes responses using as many threads as the client can muster. I'm constantly finding myself throttled by garbage collection (and/or lack thereof), and in most cases, it comes down to strings that I'm instantiating only to pass them off to a Regex or an Xml parsing routine.
If you decompile the Regex class, you'll see that internally, it uses StringBuilders to do nearly everything, but you can't pass it a string builder; it helpfully dives down into private methods before starting to use them, so extension methods aren't going to solve it either. You're in a similar situation if you want to get an object graph out of the parser in System.Xml.Linq.
This is not a case of pedantic over-optimization-in-advance. I've looked at the Regex replacements inside a StringBuilder question and others. I've also profiled my app to see where the ceilings are coming from, and using Regex.Replace() now is indeed introducing significant overhead in a method chain where I'm trying to hit a server with millions of requests per hour and examine XML responses for errors and embedded diagnostic codes. I've already gotten rid of just about every other inefficiency that's throttling the throughput, and I've even cut a lot of the Regex overhead out by extending StringBuilder to do wildcard find/replace when I don't need capture groups or backreferences, but it seems to me that someone would have wrapped up a custom StringBuilder (or better yet, Stream) based Regex and Xml parsing utility by now.
Ok, so rant over, but am I going to have to do this myself?
Update: I found a workaround which lowered peak memory consumption from multiple gigabytes to a few hundred megs, so I'm posting it below. I'm not adding it as an answer because a) I generally hate to do that, and b) I still want to find out if someone takes the time to customize StringBuilder to do Regexes (or vice-versa) before I do.
In my case, I could not use XmlReader because the stream I am ingesting contains some invalid binary content in certain elements. In order to parse the XML, I have to empty out those elements. I was previously using a single static compiled Regex instance to do the replace, and this consumed memory like mad (I'm trying to process ~300 10KB docs/sec). The change that drastically reduced consumption was:
I added the code from this StringBuilder Extensions article on
CodeProject for the handy IndexOf method.
I added a (very) crude WildcardReplace method that allows one wildcard character (* or ?) per invocation
I replaced the Regex usage with a WildcardReplace() call to empty the contents of the offending elements
This is very unpretty and tested only as far as my own purposes required; I would have made it more elegant and powerful, but YAGNI and all that, and I'm in a hurry. Here's the code:
/// <summary>
/// Performs basic wildcard find and replace on a string builder, observing one of two
/// wildcard characters: * matches any number of characters, or ? matches a single character.
/// Operates on only one wildcard per invocation; 2 or more wildcards in <paramref name="find"/>
/// will cause an exception.
/// All characters in <paramref name="replaceWith"/> are treated as literal parts of
/// the replacement text.
/// </summary>
/// <param name="find"></param>
/// <param name="replaceWith"></param>
/// <returns></returns>
public static StringBuilder WildcardReplace(this StringBuilder sb, string find, string replaceWith) {
if (find.Split(new char[] { '*' }).Length > 2 || find.Split(new char[] { '?' }).Length > 2 || (find.Contains("*") && find.Contains("?"))) {
throw new ArgumentException("Only one wildcard is supported, but more than one was supplied.", "find");
}
// are we matching one character, or any number?
bool matchOneCharacter = find.Contains("?");
string[] parts = matchOneCharacter ?
find.Split(new char[] { '?' }, StringSplitOptions.RemoveEmptyEntries)
: find.Split(new char[] { '*' }, StringSplitOptions.RemoveEmptyEntries);
int startItemIdx;
int endItemIdx;
int newStartIdx = 0;
int length;
while ((startItemIdx = sb.IndexOf(parts[0], newStartIdx)) > 0
&& (endItemIdx = sb.IndexOf(parts[1], startItemIdx + parts[0].Length)) > 0) {
length = (endItemIdx + parts[1].Length) - startItemIdx;
newStartIdx = startItemIdx + replaceWith.Length;
// With "?" wildcard, find parameter length should equal the length of its match:
if (matchOneCharacter && length > find.Length)
break;
sb.Remove(startItemIdx, length);
sb.Insert(startItemIdx, replaceWith);
}
return sb;
}
Here try this. Everything's char based and relatively low level for efficiency. Any number of your *s or ?s can be used. However, your * is now ✪ and your ? is now ★. Around three days of work went into this to make it as clean as possible. You can even enter multiple queries on one sweep!
Example usage: wildcard(new StringBuilder("Hello and welcome"), "hello✪w★l", "be") results in "become".
////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////// Search for a string/s inside 'text' using the 'find' parameter, and replace with a string/s using the replace parameter
// ✪ represents multiple wildcard characters (non-greedy)
// ★ represents a single wildcard character
public StringBuilder wildcard(StringBuilder text, string find, string replace, bool caseSensitive = false)
{
return wildcard(text, new string[] { find }, new string[] { replace }, caseSensitive);
}
public StringBuilder wildcard(StringBuilder text, string[] find, string[] replace, bool caseSensitive = false)
{
if (text.Length == 0) return text; // Degenerate case
StringBuilder sb = new StringBuilder(); // The new adjusted string with replacements
for (int i = 0; i < text.Length; i++) { // Go through every letter of the original large text
bool foundMatch = false; // Assume match hasn't been found to begin with
for(int q=0; q< find.Length; q++) { // Go through each query in turn
if (find[q].Length == 0) continue; // Ignore empty queries
int f = 0; int g = 0; // Query cursor and text cursor
bool multiWild = false; // multiWild is ✪ symbol which represents many wildcard characters
int multiWildPosition = 0;
while(true) { // Loop through query characters
if (f >= find[q].Length || (i + g) >= text.Length) break; // Bounds checking
char cf = find[q][f]; // Character in the query (f is the offset)
char cg = text[i + g]; // Character in the text (g is the offset)
if (!caseSensitive) cg = char.ToLowerInvariant(cg);
if (cf != '★' && cf != '✪' && cg != cf && !multiWild) break; // Break search, and thus no match is found
if (cf == '✪') { multiWild = true; multiWildPosition = f; f++; continue; } // Multi-char wildcard activated. Move query cursor, and reloop
if (multiWild && cg != cf && cf != '★') { f = multiWildPosition + 1; g++; continue; } // Match since MultiWild has failed, so return query cursor to MultiWild position
f++; g++; // Reaching here means that a single character was matched, so move both query and text cursor along one
}
if (f == find[q].Length) { // If true, query cursor has reached the end of the query, so a match has been found!!!
sb.Append(replace[q]); // Append replacement
foundMatch = true;
if (find[q][f - 1] == '✪') { i = text.Length; break; } // If the MultiWild is the last char in the query, then the rest of the string is a match, and so close off
i += g - 1; // Move text cursor along by the amount equivalent to its found match
}
}
if (!foundMatch) sb.Append(text[i]); // If a match wasn't found at that point in the text, then just append the original character
}
return sb;
}
XmlReader is a stream-based XML parser. See http://msdn.microsoft.com/en-us/library/756wd7zs.aspx
The Mono project has switched the license for their core libraries to an MIT X11 license. If you need to create a regex library customized for performance in your particular application, you should be able to start with the latest code from Mono's implementation of the System library.

Categories

Resources