Notifications
Clear all

[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!

9 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

2 Replies
(@aaandres)
Joined: 10 months ago

Posts: 0

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.

(@denist)
Joined: 10 months ago

Posts: 0

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

I see… Thanks!

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.

1 Reply
(@sugz)
Joined: 10 months ago

Posts: 0

I’m definitely interested in anything you can share in C# (for 3ds max or not btw)