[Closed] Strings 'WildCard' matching
Perhaps someone can be interested in… :rolleyes:
Here’s a function to check strings using old wild cards syntax:
(
Global WildCardMatch
fn compileCString =
(
CStringClassName = "PathScripts.CString"
classStr = (
"
using System;
using System.Text.RegularExpressions;
namespace PathScripts
{
public class CString
{
// Convert WildCards '*' and '?' to Regex.
// By Dmitry Bychenko ( http://stackoverflow.com/questions/30299671/matching-strings-with-wildcard)
private static string WildCardToRegular(string value, bool ci = true)
{
string regExpression;
if (ci) regExpression = \"(?i)\"; else regExpression = \"\";
return (regExpression + \"^\" + Regex.Escape(value).Replace(\"\\\\?\", \".\").Replace(\"\\\\*\", \".*\") + \"$\");
}
public static bool WildCardMatch(string myString, string myWildCardString, bool ci = true)
{
return (Regex.IsMatch(myString, WildCardToRegular(myWildCardString, ci)));
}
}
}"
)
compilerParams = dotnetobject "System.CodeDom.Compiler.CompilerParameters"
dotnet.setlifetimecontrol compilerParams #dotnet
compilerParams.ReferencedAssemblies.Add("System.dll");
compilerParams.GenerateInMemory = on
csharpProvider = dotnetobject "Microsoft.CSharp.CSharpCodeProvider"
compilerResults = csharpProvider.CompileAssemblyFromSource compilerParams #(classStr)
dotnet.setlifetimecontrol compilerResults #dotnet
compilerResults.CompiledAssembly
)
CString = (compileCString()).CreateInstance "PathScripts.CString"
fn WildCardMatch myString myWildCardString ci:ON = CString.WildCardMatch myString myWildCardString ci
)
/* Examples of use:
WildCardMatch "Hello World" "*D" --> true
WildCardMatch "Hello World" "*D" ci:OFF --> false
WildCardMatch "Hello World" "*e*w*" --> true
WildCardMatch "Hello World" "*e*w*" ci:OFF --> false
WildCardMatch "Hello World" "??llo*" --> true
WildCardMatch "Hello World" "?llo*" --> false
*/
If you aren’t interested, don’t worry. I’m so used to have no replies!
Interesting that looks like a nice middle-ground between the 3dsmax matchPattern function and full user-unfriendly regex.
I’d keep your case parameter in the same format as the matchpattern for more user friendlyness. I couldn’t work out what ic stood for until I looked at the maxscript help!
ignoreCase:<boolean>
I find your posts very interesting, it’s clear you come from a very different background to most of us, with a much more formal programming style. lambda confused me lots when I learned other languages and your LINQ stuff doesn’t seem significantly more friendly to warrant the implementation. I always try to keep my dependencies and script library usage down to a minimum to make it easier to distribute tools and be able to use them off-site so these massive functions would add a fair bit of weight to anything I might upload.
Very nice, thanks for sharing !
One question though, why not putting this kind of method in a c# assembly instead of compiling it on the fly ?
Thanks for your answer, Dave.
In fact, ‘ci’ is not “ignore Case” but “case Insensitive”.
I allways try for these optional parameters to use a short word.
When I’ve said I’m used to have no replies, I was thinking not only in ‘maxLINQ’ but in some threads from people asking for help and saying absolutely nothing. Some recent examples:
sorting files according dates in MXS: http://forums.cgsociety.org/showthread.php?t=1439438
Custom new attributes?: http://forums.cgsociety.org/showthread.php?t=1436899
Don’t add duplicates to a dotnet listview – help please: http://forums.cgsociety.org/showthread.php?t=1437445
For maxLINQ, I understand your point of view.
I think it’s more a friendly tool to make quick queries in the Listener while working or coding, or just for internal scripts. It’s not easy to write for-loops in the Listener when you need more than one line. maxLINQ gives a funny solution.
For distribution scripts, it has no much sense as any programer can do the same and more specific for his needs in a few couple of lines.
Thanks @Sugari.
It’s just a way for me to have all together and, if needed, include the code in a script in case I have to share or distribute it.
do you know that in general matchpattern is about two times faster than your WildCardMatch?
one solution for ‘wildcard’ used in a loop might be compiled regex
Yes, of course. But I needed it inside C# so I did it.
And I thought that ‘matchPattern’ was only valid starting with a character (I suppose fault of the Help examples).
I don’t understand what do you mean.
https://msdn.microsoft.com/en-us/library/8zbs0h2f(v=vs.110).aspx
you can compile regular expression as an object and use it in loop instead of do compilation on every loop iteration
This function can give you lots of happiness for searching items inside a string or file.
(
Global FindAllWC
fn compileCString =
(
classStr = (
"
using System;
using System.Text.RegularExpressions;
namespace PathScripts
{
public class CString
{
private static string WildCardToRegularAll(string value, bool ci = true, bool word = false)
{
string regExpression;
if (ci) regExpression = \"(?i)\"; else regExpression = \"\";
if (word)
{
return (regExpression + \"(\\\\b\" + Regex.Escape(value).Replace(\"\\\\?\", \"\\\\w\").Replace(\"\\\\*\", \"\\\\w*\") + \")\");
}
else
{
return (regExpression + \"(\" + Regex.Escape(value).Replace(\"\\\\?\", \".\").Replace(\"\\\\*\", \".*?\") + \")\");
}
}
public static string[] FindAllWC(string myString, string myWildCardString, bool ci = true, bool word = false)
{
MatchCollection theMatches = (Regex.Matches(myString, WildCardToRegularAll(myWildCardString, ci, word)));
string[] result = new string[theMatches.Count];
int index = -1;
foreach (Match match in theMatches)
{
index++;
result[index] = match.Value;
}
return result;
}
public static int[][] FindAllWCID(string myString, string myWildCardString, bool ci = true, bool word = false)
{
MatchCollection theMatches = (Regex.Matches(myString, WildCardToRegularAll(myWildCardString, ci, word)));
int[][] result = new int[theMatches.Count][];
int index = -1;
foreach (Match match in theMatches)
{
index++;
int[] valuePair = new int[2];
valuePair[0] = match.Index + 1; valuePair[1] = match.Length;
result[index] = valuePair;
}
return result;
}
}
}"
)
compilerParams = dotnetobject "System.CodeDom.Compiler.CompilerParameters"
dotnet.setlifetimecontrol compilerParams #dotnet
compilerParams.ReferencedAssemblies.Add("System.dll");
compilerParams.GenerateInMemory = on
csharpProvider = dotnetobject "Microsoft.CSharp.CSharpCodeProvider"
compilerResults = csharpProvider.CompileAssemblyFromSource compilerParams #(classStr)
dotnet.setlifetimecontrol compilerResults #dotnet
compilerResults.CompiledAssembly
)
CString = (compileCString()).CreateInstance "PathScripts.CString"
/*
FindAllWC
strLINQ.FindAllWC <string> <WildCardString> [ci:<boolean>] [word:<boolean>] [id:<boolean>]:
--> returns a stringArray corresponding to all the matches of the 'WildCardString' pattern in the string. Void stringArray #() if no match
** ci: case insensitive comparison (default TRUE)
** word: searchs only for whole words (default FALSE)
** id: returns an array of value-pairs #(index of the match, length of the matched string), #() if no match. (default FALSE)
*/
fn FindAllWC myString myWildCardString ci:ON word:OFF id:OFF = if (id) then (CString.FindAllWCID myString myWildCardString ci word) else (CString.FindAllWC myString myWildCardString ci word)
)
Examples of use:
findAllWC "this is <jjj> and this is <kkkk>" "<*>" --> returns #("<jjj>", "<kkkk>")
findAllWC "this is <jjj> and this is <kkkk>" "<*>" id:on --> returns #(#(9, 5), #(27, 6))
If someone is interested in, I have more than 60 useful functions based in C# for querying strings and string arrays.