RowFilter LIKE operation - c#

I know that the following is not allowed as a row filter
'canada%.txt' or 'canada*.txt'
and I guess I can rewrite my filter as
file_name like 'Canada%' and file_name like '%.txt'
should work.
But is there an easier way instead of determing where the % is and spliting the string?

I don't believe that CHARINDEX is allowed in the filter expression.
You might try to dynamically build the filter string from C# (very much untested, but here's a possible syntax):
//split the original string using the wildcard as the delimiter
string[] f = s.Split('%');
//use the resulting array to build the resultstring
string resultstring = 'file_name like "' + f[0] + '%" and file_name like "%' + f[1] + '"'
//view.RowFilter = resultstring;

Here is the solution that I came up with
private string CreateRowFilter(string remoteFilePattern)
{
string[] pattern = remoteFilePattern.Split(new char[] { '*', '%' });
int length = pattern.GetUpperBound(0);
if (length == 0)
{
return String.Format("Name = '{0}'", pattern[0]);
}
StringBuilder fileter = new StringBuilder(
String.Format("Name LIKE '{0}*' ", pattern[0]));
for (int segment = 1; segment < length; segment++)
{
fileter.Append(
String.Format("AND Name LIKE '*{0}*' ", pattern[segment]));
}
if(String.IsNullOrEmpty(pattern[length]) == false)
{
fileter.Append(
String.Format("AND Name LIKE '*{0}' ", pattern[length]));
}
return fileter.ToString();
}

Related

Dynamic library (System.Linq.Dynamic) SQL LIKE Operator

Someone has posted a similar question here How Dynamic library (System.Linq.Dynamic) support LIKE Operator?
But it's not exactly what I want. The Contains operator mentioned in that post only do this in SQL "%SOMETHING%". But the LIKE operator in SQL can do this "SOME%THING". Is there a similar operator for Dynamic LINQ? If not, is there a solution for this? Maybe with Regex? Also is there a single character wildcard? E.g. "SOM$THING" returns "SOMETHING" or "SOM3THING"
Edit: I am developing a WPF application which should read log files in XML format. Each element contains 34 fields. So instead of writing a very long WHERE, I have used System.Reflection.PropertyInfo to iterate each field to write the query and then use System.Linq.Dynamic to execute it.
Edit2: I have edited the code so it's more readable for the viewers.
Here is some code:
Example 1:
prop.Name = "FirstName", paramterString = "Ke%in", returns "Kevin",
"Kelvin"...
Example 2:
prop.Name = "FirstName", paramterString = "Ke$in", returns "Kevin",
"Kelin"...
var query = "";
StringBuilder sb = new StringBuilder();
foreach (var prop in stringProps)
{
sb.Append($"({prop.Name} != null And {prop.Name}.Contains({parameterString})");
}
query = sb.ToString().Substring(0, sb.Length - 4);
filteredData = filteredData.Where(query);
One of the requirement is to implement a SQL LIKE operator, so the users can use something like this to get the result they want: FirstName LIKE 'SOME%THING'
Since there is no LIKE operator in Dynamic Linq library, I have created it my own version. The code is not pretty, but it does work. Hopefully someone can optimize it or suggest a better way to do this.
public string ParseWildcardInParameterString(string parameter, string propertyName)
{
string stringWithWildcard = parameter;
if (parameter.Contains("%") || parameter.Contains("$"))
{
stringWithWildcard = parameter;
string[] substrings = parameter.Split(new Char[] { '%', '$' }, StringSplitOptions.RemoveEmptyEntries);
string[] wildcards = ParseWildcards(parameter);
if (substrings.Any())
{
StringBuilder sb = new StringBuilder();
int substringsCount = substrings.Length;
for (int i = 0; i < substringsCount; i++)
{
if (!substrings[i].EndsWith("\\"))
{
int index = parameter.IndexOf(substrings[i]);
if (i < substringsCount - 1)
{
index = parameter.IndexOf(substrings[i + 1], index + 1);
if (index > -1)
{
string secondPart = wildcards[i].Equals("%") ?
$"{propertyName}.IndexOf(\"{substrings[i + 1]}\", {propertyName}.IndexOf(\"{substrings[i]}\") + \"{substrings[i]}\".Length) > -1" :
$"{propertyName}.IndexOf(\"{substrings[i + 1]}\", {propertyName}.IndexOf(\"{substrings[i]}\") + \"{substrings[i]}\".Length + 1) == {propertyName}.IndexOf(\"{substrings[i]}\") + \"{substrings[i]}\".Length + 1";
sb.Append($"({propertyName}.IndexOf(\"{substrings[i]}\") > -1 And {secondPart}) And ");
}
}
}
}
stringWithWildcard = sb.Remove(sb.Length - 5, 5).Append(") Or ").ToString();
}
}
return stringWithWildcard;
}
private string[] ParseWildcards(string parameter)
{
IList<string> wildcards = new List<string>();
foreach (var chararcter in parameter.ToCharArray())
{
if (chararcter.Equals('%') || chararcter.Equals('$'))
{
wildcards.Add(chararcter.ToString());
}
}
return wildcards.ToArray();
}
Can you try if the Like functionality in System.Linq.Dynamic.Core does work for you?
Code example would be:
var dynamicFunctionsLike1 = context.Cars.Where(config, "DynamicFunctions.Like(Brand, \"%a%\")");
For full example, see ConsoleAppEF2.1.1/Program.cs

Fast multi-string replacement

I need to perform multi string replacement. I have a string where several parts need to be changed according to substitution map.
All replacement must be done in one action - it means if "a" should be replaced with "b" and also "b" must be replaced with "c" and input string is "abc", the result will be "bcc"
I have a sollution based on building regex and then replacing all matches. I wrote it some time ago, now I'm refactoring the code and not so satisfied with it. Is there better (faster, simplier) sollution?
This is what I have:
public static string Replace(string s, Dictionary<string, string> substitutions)
{
string pattern = "";
int i = 0;
foreach (string ch in substitutions.Keys)
{
if (i == 0)
pattern += "(" + Regex.Escape(ch) + ")";
else
pattern += "|(" + Regex.Escape(ch) + ")";
i++;
}
var r = new Regex(pattern);
var parts = r.Split(s);
string ret = "";
foreach (string part in parts)
{
if (part.Length == 1 && substitutions.ContainsKey(part[0].ToString()))
{
ret += substitutions[part[0].ToString()];
}
else
{
ret += part;
}
}
return ret;
}
And test case:
var test = "test aabbcc";
var output = Replace(test, new Dictionary<string, string>{{"a","b"},{"b","y"}});
Assert.That(output=="test bbyycc");
You can replace all this with
var r = new Regex(string.Join("|", substitutions.Keys.Select(k => "(" + k + ")")));
return r.Replace(s, m => substitutions[m.Value]);
The key things are making use of the string.Join method rather than implementing it yourself, and making use of this Regex.Replace overload and delegates to do the replacement.

get values from array and add into one string

Object Book has Author which has property Name of type string.
I want to iterate trough all Authors and add it's Name string to the one string (not array) separated by comma, so this string should be at the as
string authorNames = "Author One, Author two, Author three";
string authorNames = string.Empty;
foreach(string item in book.Authors)
{
string fetch = item.Name;
??
}
You can use the string.Join function with LINQ
string authorNames = string.Join(", ", book.Authors.Select(a => a.Name));
You can use
string authors = String.Join(", ", book.Authors.Select(a => a.Name));
LINQ is the way to go in C#, but for explanatory purposes here is how you could code it explicitly:
string authorNames = string.Empty;
for(int i = 0; i < book.Authors.Count(); i++)
{
if(i > 0)
authorNames += ", ";
authorNames += book.Authors[i].Name;
}
You could also loop through them all, and append them to authorNames and add a comma in the end, and when it's done simply trim of the last comma.
string authorNames = string.Empty;
foreach(string author in book.Authors)
{
string authorNames += author.Name + ", ";
}
authorNames.TrimEnd(',');
Using LinQ, there are plenty of ways to merge multiple string into one string.
book.Authors.Select(x => x.Name).Aggregate((x, y) => x + ", " + y);
To anwsers James' comment
[TestMethod]
public void JoinStringsViaAggregate()
{
var mystrings = new[] {"Alpha", "Beta", "Gamma"};
var result = mystrings.Aggregate((x, y) => x + ", " + y);
Assert.AreEqual("Alpha, Beta, Gamma", result);
}

Extract node value from xml resembling string C#

I am having strings like below
<ad nameId="\862094\"></ad>
or comma seprated like below
<ad nameId="\862593\"></ad>,<ad nameId="\862094\"></ad>,<ad nameId="\865599\"></ad>
How to extract nameId value and store in single string like below
string extractedValues ="862094";
or in case of comma seprated string above
string extractedMultipleValues ="862593,862094,865599";
This is what I have started trying with but not sure
string myString = "<ad nameId="\862593\"></ad>,<ad nameId="\862094\"></ad>,<ad
nameId="\865599\"></ad>";
string[] myStringArray = myString .Split(',');
foreach (string str in myStringArray )
{
xd.LoadXml(str);
chkStringVal = xd.SelectSingleNode("/ad/#nameId").Value;
}
Search for:
<ad nameId="\\(\d*)\\"><\/ad>
Replace with:
$1
Note that you must search globally. Example: http://www.regex101.com/r/pL2lX1
Please see code below to extract all numbers in your example:
string value = #"<ad nameId=""\862093\""></ad>,<ad nameId=""\862094\""></ad>,<ad nameId=""\865599\""></ad>";
var matches = Regex.Matches(value, #"(\\\d*\\)", RegexOptions.RightToLeft);
foreach (Group item in matches)
{
string yourMatchNumber = item.Value;
}
Try like this;
string s = #"<ad nameId=""\862094\""></ad>";
if (!(s.Contains(",")))
{
string extractedValues = s.Substring(s.IndexOf("\\") + 1, s.LastIndexOf("\\") - s.IndexOf("\\") - 1);
}
else
{
string[] array = s.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
string extractedMultipleValues = "";
for (int i = 0; i < array.Length; i++)
{
extractedMultipleValues += array[i].Substring(array[i].IndexOf("\\") + 1, array[i].LastIndexOf("\\") - array[i].IndexOf("\\") - 1) + ",";
}
Console.WriteLine(extractedMultipleValues.Substring(0, extractedMultipleValues.Length -1));
}
mhasan, here goes an example of what you need(well almost)
EDITED: complete code (it's a little tricky)
(Sorry for the image but i have some troubles with tags in the editor, i can send the code by email if you want :) )
A little explanation about the code, it replaces all ocurrences of parsePattern in the given string, so if the given string has multiple tags separated by "," the final result will be the numbers separated by "," stored in parse variable....
Hope it helps

How do I iterate "between" items in an array / collection / list?

This problem has bugged me for years, and I always feel like I'm coming up with a hack when there's a much better solution. The issue at hand occurs when you want to do something to all items in a list and then add something inbetween those items. In short, I want to:
Do something to every item in the list.
Do something else to all but the last item in the list (in effect, do something "inbetween" the items in the list).
For example, let's say I have a class called Equation:
public class Equation
{
public string LeftSide { get; set; }
public string Operator { get; set; }
public string RightSide { get; set; }
}
I want to iterate over a list of Equations and return a string that formats these items together; something like the following:
public string FormatEquationList(List<Equation> listEquations)
{
string output = string.Empty;
foreach (Equation e in listEquations)
{
//format the Equation
string equation = "(" + e.LeftSide + e.Operator + e.RightSide + ")";
//format the "inbetween" part
string inbetween = " and ";
//concatenate the Equation and "inbetween" part to the output
output += equation + inbetween;
}
return ouput;
}
The problem with the above code is that it is going to include and at the end of the returned string. I know that I could hack some code together, replace the foreach with a for loop, and add the inbetween element only if it's not the last item; but this seems like a hack.
Is there a standard methodology for how to deal with this type of problem?
You basically have a few different strategies for dealing with this kind problem:
Process the first (or last) item outside of the loop.
Perform the work and then "undo" the extraneous step.
Detect that your're processing the first or last item inside the loop.
Use a higher-level abstraction that allows you to avoid the situation.
Any of these options can be a legitimate way to implement a "between the items" style of algorithm. Which one you choose depends on things like:
which style you like
how expensive "undoing work" is
how expensive each "join" step is
whether there are any side effects
Amongst other things. For the specific case of string, I personally prefer using string.Join(), as I find it illustrates the intent most clearly. Also, in the case of strings, if you aren't using string.Join(), you should try to use StringBuilder to avoid creating too many temporary strings (a consequence of strings being immutable in .Net).
Using string concatentation as the example, the different options break down into examples as follows. (For simplicity, assume Equation has ToString() as: "(" + LeftSide + Operator + RightSide + ")"
public string FormatEquation( IEnumerable<Equation> listEquations )
{
StringBuilder sb = new StringBuilder();
if( listEquations.Count > 0 )
sb.Append( listEquations[0].ToString() );
for( int i = 1; i < listEquations.Count; i++ )
sb.Append( " and " + listEquations[i].ToString() );
return sb.ToString();
}
The second option looks like:
public string FormatEquation( IEnumerable<Equation> listEquations )
{
StringBuilder sb = new StringBuilder();
const string separator = " and ";
foreach( var eq in listEquations )
sb.Append( eq.ToString() + separator );
if( listEquations.Count > 1 )
sb.Remove( sb.Length, separator.Length );
}
The third would look something like:
public string FormatEquation( IEnumerable<Equation> listEquations )
{
StringBuilder sb = new StringBuilder();
const string separator = " and ";
foreach( var eq in listEquations )
{
sb.Append( eq.ToString() );
if( index == list.Equations.Count-1 )
break;
sb.Append( separator );
}
}
The last option can take multiple forms in .NET, using either String.Join or Linq:
public string FormatEquation( IEnumerable<Equation> listEquations )
{
return string.Join( " and ", listEquations.Select( eq => eq.ToString() ).ToArray() );
}
or:
public string FormatEquation( IEnumerable<Equation> listEquations )
{
return listEquations.Aggregate((a, b) => a.ToString() + " and " + b.ToString() );
}
Personally, I avoid using Aggregate() for string concatenation because it results in many intermediate, discarded strings. It's also not the most obvious way to "join" a bunch of results together - it's primarily geared for computing a "scalar" results from a collection in some arbitrary, caller-defined fashion.
You can use String.Join().
String.Join(" and ",listEquations.Select(e=>String.Format("({0}{1}{2})",e.LeftSide,e.Operator,e.RightSide).ToArray());
You can do this with LINQ's Aggregate operator:
public string FormatEquationList(List<Equation> listEquations)
{
return listEquations.Aggregate((a, b) =>
"(" + a.LeftSide + a.Operator + a.RightSide + ") and (" +
b.LeftSide + b.Operator + b.RightSide + ")");
}
Using a for loop with counter is perfectly reasonable if you don't want a foreach loop. This is why there is more than one type of looping statement.
If you want to process items pairwise, loop at LINQ's Aggregate operator.
I usualy add it before the condition, and check if its the 1st item.
public string FormatEquationList(List<Equation> listEquations)
{
string output = string.Empty;
foreach (Equation e in listEquations)
{
//use conditional to insert your "between" data:
output += (output == String.Empty) ? string.Empty : " and ";
//format the Equation
output += "(" + e.LeftSide + e.Operator + e.RightSide + ")";
}
return ouput;
}
I have to say I would look at the string.Join() function as well, +1 for Linqiness on that. My example is a more of a traditional solution.
I generally try to prefix separators based on a condition rather than add them to the end.
string output = string.Empty;
for (int i = 0; i < 10; i++)
{
output += output == string.Empty ? i.ToString() : " and " + i.ToString();
}
0 and 1 and 2 and 3 and 4 and 5 and 6 and 7 and 8 and 9
I like the String.Join method already posted.
But when you're not using an Array this has normally been my solution to this problem:
public string FormatEquationList(List<Equation> listEquations)
{
string output = string.Empty;
foreach (Equation e in listEquations)
{
// only append " and " when there's something to append to
if (output != string.Empty)
output += " and ";
output += "(" + e.LeftSide + e.Operator + e.RightSide + ")";
}
return output;
}
Of course, it's usually faster to use a StringBuilder:
public string FormatEquationList(List<Equation> listEquations)
{
StringBuilder output = new StringBuilder();
foreach (Equation e in listEquations)
{
// only append " and " when there's something to append to
if (output.Length > 0)
output.Append(" and ");
output.Append("(");
output.Append(e.LeftSide);
output.Append(e.Operator);
output.Append(e.RightSide);
output.Append(")");
}
return output.ToString();
}

Categories