Multiple Expression.Or - c#

How to build an expression which will produce the following statement?
x => x.Parameter1 == "Some text" || x.Parameter2 == "Some text" || x.Parameter3 == "Some text"
It's not hard to do x =>, but how to create those many OR operators?
I know we have Expression.Or method, but it only accepts 2 arguments.
Thanks.

So you just compile them together
psuedo code:
firstOr = Expression.OrElse(x.Parameter2 == "some test", x.Parameter3 == "sometest")
secondOr = Expression.OrElse(firstOr, x.Parameter1 == "Some text");
Then all you do is evaluate the secondOr
These are expression trees , and therefor you compose them together.
when you have multiple elements, segment as you would with a mathematical expression, put parenthesis around parts:
1 + 2 + 5 = 8
this is
(1 + 2) + 5 = 8
So we've turned 1 expression into a composition of 2 expressions.

It looks like you'd better use the Expression.OrElse() method. The method Expression.Or() represents a bitwise OR operation, i.e. x.Parameter1 == "Some text" | x.Parameter2 == "Some text"
var condition1 = Expression.Equal(Expression.Parameter(typeof(string), "parameter1"),
Expression.Constant("Some text 1"));
var condition2 = Expression.Equal(Expression.Parameter(typeof(string), "parameter2"),
Expression.Constant("Some text 2"));
var condition3 = Expression.Equal(Expression.Parameter(typeof(string), "parameter3"),
Expression.Constant("Some text 3"));
var result = Expression.OrElse(condition1, Expression.OrElse(condition2, condition3));

Related

Regex replacement in a custom tag

I have a string that may contain one or more of the following tags:
<CHOICE [some words] [other words]>
I need to replace (C#) all occurrences of this tag as follows:
Example: I like <CHOICE [cars and bikes] [apple and oranges]>
Result: I like cars and bikes
Example: I like <CHOICE [cars and bikes] [apple and oranges]>, I also like <CHOICE [pizza] [pasta]>
Result: I like cars and bikes, I also like pizza
Basically, replace the entire tag with only the string appearing in the first set of brackets.
Looks like capture groups is the way to go but I wasn't able to understand how to make them work.
Any help is appreciated!
EDIT: Regex is not a requirement, I thought it would be the best approach, but I see some comments telling me that it's not needed so any other suggestion will be just as fine. Thanks!
Just for fun. Here is a school-yard foreach state-machine, with a linear O(n) time complexity.
var line = "I like <CHOICE [cars and bikes] [apple and oranges]>";
var result = new StringBuilder();
var state = 0;
foreach (char c in line)
{
if (state == 0 && c == '<') state = 1;
else if (state == 1 && c == '[') state = 2;
else if (state == 2 && c == ']') state = 3;
else if (state == 3 && c == '>') state = 0;
else if (state == 0 || state == 2) result.Append(c);
};
Output
I like cars and bikes
Demo here
Get groups of Matches First, then for each Matched Group replace a first string in [ and ]
MatchCollection matches = Regex.Matches(InputStr, #"<CHOICE(.*?)>");
foreach(Match Item in matches)
{
MatchCollection matches1 = Regex.Matches(Item.ToString(), #"\[(.+?)]");
string FirstOccurence = matches1[0].Groups[1].ToString();
InputStr = InputStr.Replace(Item.ToString(), FirstOccurence);
}
Find the demo
string pattern = #"\< *CHOICE *((\[(?<choice>[a-zA-Z0-9 ]+)\]) *)+ *>";
Regex regex = new Regex(pattern);
string source = "I like <CHOICE [cars and bikes] [apple and oranges]>";
var match = regex.Match(source);
if (match.Success)
{
for (int i = 0; i < match.Groups["choice"].Captures.Count; i++)
{
Debug.WriteLine(match.Groups["choice"].Captures[i]);
}
string replaced = regex.Replace(source, match.Groups["choice"].Captures[0].Value);
Debug.WriteLine(replaced);
}
The output is:
cars and bikes
apple and oranges
I like cars and bikes
\< *CHOICE *
matches "<" "zero or more spaces" "CHOICE" "zero or more spaces"
([a-zA-Z0-9 ]+)
matches words and spaces
?<choice>
gives above group a name:choice
\[(?<choice>[a-zA-Z0-9 ]+)\]
matches one choice in []
((\[(?<choice>[a-zA-Z0-9 ]+)\] *)
matches choices separated by zero or more spaces
+
means you should have at lease one choice
*>
you can have zero or more spaces at the end before ">"
I assume this is the best way to do that.
string text = "This is some dummy text with the choice < CHOICE [ white black green cyan ] [yellow green]>." +
" The second choice <CHOICE [pink brown red] [blue cyan]>.";
string pattern = #"<\s*?CHOICE\s*\[\s*?(.+?)\s*?\].*?>";
var result = Regex.Replace(text, pattern, r => String.Join(" and ", r.Groups[1].Value.Split(' ', StringSplitOptions.RemoveEmptyEntries)));
Console.WriteLine(result);
Output
This is some dummy text with the choice white and black and green and cyan. The second choice pink and brown and red.

How can I simplify and Optimize this lambda expression?

I'm trying to simplify and optimize the following lambda expression. My requirement is to get the first lead whose mobile phone or telephone1 matches intakePhoneNum. I want to match first 10 digits only.
Entity matchingLead =
allLeads.Where(l =>
(l.Attributes.Contains("mobilephone") &&
(Regex.Replace(l.Attributes["mobilephone"].ToString(), "[^0-9]", "").Length >=10
? Regex.Replace(l.Attributes["mobilephone"].ToString(), "[^0-9]", "").Substring(0,9)
: Regex.Replace(l.Attributes["mobilephone"].ToString(), "[^0-9]", "").Substring(0)).Equals(intakePhoneNum))||
(l.Attributes.Contains("address1_telephone1") &&
(Regex.Replace(l.Attributes["address1_telephone1"].ToString(), "[^0-9]", "").Length >= 10
? Regex.Replace(l.Attributes["address1_telephone1"].ToString(), "[^0-9]", "").Substring(0, 9)
: Regex.Replace(l.Attributes["address1_telephone1"].ToString(), "[^0-9]", "").Substring(0)).Equals(intakePhoneNum))).FirstOrDefault();
First, I would suggest to introduce variables for the attributes.
Then, instead of the differentiation between Length >= 10 and Length < 10, simple use StartsWith.
And last, instead of Where(...).FirstOrDefault, simply use FirstOrDefault(...)
Entity matchingLead =
allLeads.FirstOrDefault(l =>
{
if (l.Attributes.Contains("mobilephone"))
{
var phone = Regex.Replace(l.Attributes["mobilephone"].ToString(), "[^0-9]", "");
if (phone.StartsWith(intakePhoneNum))
return true;
}
if (l.Attributes.Contains("address1_telephone1"))
{
var phone = Regex.Replace(l.Attributes["address1_telephone1"].ToString(), "[^0-9]", "");
if (phone.StartsWith(intakePhoneNum))
return true;
}
return false;
});

Comparing to strings but no effect

So I have a list of terminals: a, b, c, d
I have a production like
A > aA | cC |a
I'm trying to check if a part of production A is a terminal or if that part exists in list of terminals. The problem is that when I compare the two parts the result is always false. I have tried with "Equals", "Contains" and "==" and the result is the same and I don't know why.
My code from where I split the production and compare the two parts:
foreach (Production production in productions)
{
String prod = production.ToString();
String[] right = prod.Trim().Split('>');
String justRightPart = right[1];
String[] separate = justRightPart.Trim().Split('|');
Boolean ok = true;
foreach (String s in separate)
{
foreach(string terminal in terminals)
{
Console.WriteLine("Terminal: " + terminal + " string part is " +s);
Boolean bool = terminal.Contains(s) || (terminal == s);
Console.WriteLine("bool : " + bool);
}
}
}
and the bool is always false even if it says:
Terminal a string part is a
Why is not equal?
Any suggestions?
There is probably whitespace in s that isn't in terminal or vice versa. Try adding single quotes around your string printing, eg:
Console.WriteLine("Terminal: '" + terminal + "' string part is '" + s + "'");
It might be clearer if you rewrite your print using positional arguments, eg:
Console.WriteLine("Terminal: '{0}' string part is '{1}'", terminal, s);
I suggest using Linq, e.g.
List<String> terminals = new List<string>() { "a", "b", "c" };
string source = "A > aA | cC | a";
var hasTerminal = source
.Substring(source.IndexOf('>') + 1) // at the right of ">"
.Split('|') // split to parts
.Select(part => part.Trim()) // trim each part (leading/trailing white spaces)
.Any(part => terminals.Contains(part)); // ... if part exists in list of terminals
You may want to implement a debugging report / log as well:
var report = source
.Substring(source.IndexOf('>') + 1)
.Split('|')
.Select(part => part.Trim())
.Select(part => $"{part,4} is {(terminals.Contains(part) ? "a term" : "NOT a term")}");
Console.Write(string.Join(Environment.NewLine, report));
The outcome is
aA is NOT a term
cC is NOT a term
a is a term

Finding symbol in text c#

I am trying to retrieve from text one of the symbols like this: "<", "=", "<=", ">", ">=", "<>", "¬=".
Example text might look like "> 10 dalk tasd ... " or
" >= 10 asdasdasd ..". There could be a lot of whitespace characters.
I am trying do something like the below, but it doesn't work:
string sign = new string(textCh.SkipWhile(c => !Char.IsSymbol('>') || !Char.IsSymbol('=') || !Char.IsSymbol('<') || !Char.IsSymbol('¬'))
.TakeWhile(c => Char.IsSymbol('=') || Char.IsSymbol('>')).ToArray());
How can i retrieve it ?
You don't want to SkipWhile(criterion OR criterion OR criterion) because a character you want to take can only be one of <, =, or >, and the criteria corresponding to the characters it is not will be true and the character will be skipped.
You could change the SkipWhile criteria to be &&, or you could use a Regex.
var sign = System.Text.RegularExpressions.Regex.Match("<[>=]?|=|>=?|¬=").Value;
To extract the first such symbol I would use
Regex.Match(myString, "<[>=]?|=|>=?|!=").Value
string example = "avasvasv>asfascvd<hrthtjh";
int firstIndex = example.IndexOfAny(new char[] { '>', '<', '-', '=' });
int lastIndex = example.Substring(firstIndex + 1).IndexOfAny(new char[] { '=', '>'});
string outPutExample = example.Substring(firstIndex + 1).Substring(0, lastIndex); // OutPut -> asfascvd

Replace all instances of '=' with '==' in a string

I have a c# string expression where i'd like to replace all instances of '=' with '=='
e.g
1 = 1
should be
1 == 1
However, I can't just do a replace('=','==') because '1 == 1' would become '1 ==== 1'
Is there a Regex or something I could use instead?
You can use a Regex which will match only a single equals sign and call Replace on that Regex.
new Regex("={1,}").Replace("=", "==")
Returns ==
new Regex("={1,}").Replace("==", "==")
Returns ==

Categories

Resources