token | 筛选器的标识符。通常为筛选器中操作符前面的部分(例如,“id>=2”中的“id”)。 |
getDataFunc | 用于获取用于筛选的对象的回调。获取类型为 TData 的对象并返回类型为 TFilter 的对象。 |
stringComparison | 字符串比较选项。 |
supportedOperatorType | 受支持的操作符令牌列表。此列表包含受支持的操作符令牌。将 null 或空列表与指示支持所有运算符相关联。 |
添加新的自定义筛选器。
<TData>:QueryEngine 筛选的数据类型。
<TFilter>:筛选器比较的数据类型。
如果您不需要自行处理运算符,请使用此重载注册基本筛选器。
// Add a filter for MyObjectType.id that supports all operators queryEngine.AddFilter("id", myObj => myObj.id); // Add a filter for MyObjectType.name that supports only contains (:), equal (=) and not equal (!=) queryEngine.AddFilter("n", myObj => myObj.name, new[] { ":", "=", "!=" }); // Add a filter for MyObjectType.active that supports only equal and not equal queryEngine.AddFilter("a", myObj => myObj.active, new[] { "=", "!=" }); // Add a filter for the computed property magnitude that supports equal, not equal, lesser, greater, lesser or equal and greater or equal. queryEngine.AddFilter("m", myObj => myObj.position.magnitude, new[] { "=", "!=", "<", ">", "<=", ">=" });
有关完整示例,请参阅 QueryEngine。
token | 筛选器的标识符。通常为筛选器中操作符前面的部分(例如,“id>=2”中的“id”)。 |
getDataFunc | 用于获取过滤器中使用的对象的回调。获取一个 TData 和 TParam 类型的对象,并返回一个 TFilter 类型的对象。 |
parameterTransformer | 用于将字符串转换成 TParam 类型的回调。解析查询时使用,将传递给函数的内容转换成正确的格式。 |
stringComparison | 字符串比较选项。 |
supportedOperatorType | 受支持的操作符令牌列表。此列表包含受支持的操作符令牌。将 null 或空列表与指示支持所有运算符相关联。 |
添加一个带参数的新自定义过滤器。
<TData>:QueryEngine 筛选的数据类型。
<TFilter>:筛选器比较的数据类型。
<TParam>:传递给过滤器的的数据类型。
如果不需要自行处理运算符,请使用此重载注册接受参数的过滤器。
using System.Collections.Generic; using System.Globalization; using System.Linq; using UnityEditor; using UnityEditor.Search; using UnityEngine; static class Example_QueryEngine_AddFilter_Param { static List<MyObjectType> s_Data; [MenuItem("Examples/QueryEngine/AddFilter_Param")] public static void RunExample() { // Set up the query engine var queryEngine = new QueryEngine<MyObjectType>(); queryEngine.SetSearchDataCallback(myObj => new[] { myObj.id.ToString(), myObj.name }); // Add a "dist" filter to filter items based on a specified distance from a position or from another item queryEngine.AddFilter("dist", (myObj, paramPosition) => { // Compute the distance from the position that was retrieved in the parameter transformer var vec = myObj.position - paramPosition; return vec.magnitude; }, paramStringValue => { // Transform the parameter from a string to a usable Vector2 // If the user specified a vector if (paramStringValue.StartsWith("[") && paramStringValue.EndsWith("]")) { paramStringValue = paramStringValue.Trim('[', ']'); var vectorTokens = paramStringValue.Split(','); var vectorValues = vectorTokens.Select(token => float.Parse(token, CultureInfo.InvariantCulture.NumberFormat)).ToList(); return new Vector2(vectorValues[0], vectorValues[1]); } // Treat the value as the name of an object var myObj = s_Data.Find(obj => obj.name == paramStringValue); return myObj.position; }, new[] { "=", "!=", "<", ">", "<=", ">=" }); s_Data = new List<MyObjectType>() { new MyObjectType { id = 0, name = "Test 1", position = new Vector2(0, 0), active = false }, new MyObjectType { id = 1, name = "Test 2", position = new Vector2(0, 1), active = true }, new MyObjectType { id = 2, name = "Test 3", position = new Vector2(1, 0), active = false }, new MyObjectType { id = 3, name = "Test 4", position = new Vector2(1.2f, 0), active = false }, }; // Find all items that are at a distance of 1 or greater to [0, 0] var query = queryEngine.ParseQuery("dist([0, 0])>=1"); var filteredData = query.Apply(s_Data).ToList(); Debug.Assert(filteredData.Count == 3, $"There should be 3 items in the filtered list but found {filteredData.Count} items."); Debug.Assert(!filteredData.Contains(s_Data[0]), "Test 1 should not be in the list as its distance to [0, 0] is < 1."); // Find all items that are at a distance smaller than 1 to "Test 3", but not "Test 3" itself query = queryEngine.ParseQuery("dist(Test 3)<1 -\"Test 3\""); filteredData = query.Apply(s_Data).ToList(); Debug.Assert(filteredData.Count == 1, $"There should be 1 item in the filtered list but found {filteredData.Count} items."); Debug.Assert(filteredData.Contains(s_Data[3]), "Test 4 should be in the list as its distance to Test 3 is < 1."); } class MyObjectType { public int id { get; set; } public string name { get; set; } = string.Empty; public Vector2 position { get; set; } = Vector2.zero; public bool active { get; set; } public override string ToString() { return $"({id}, {name}, ({position.x}, {position.y}), {active})"; } } }
token | 筛选器的标识符。通常为筛选器中操作符前面的部分(例如,“id>=2”中的“id”)。 |
filterResolver | 用于处理此过滤器的任何运算符的回调。获取一个 TData 类型的对象、运算符令牌和过滤器值,并返回一个布尔值指示过滤器是否已通过或未通过。 |
supportedOperatorType | 受支持的操作符令牌列表。此列表包含受支持的操作符令牌。将 null 或空列表与指示支持所有运算符相关联。 |
添加一个带完整解析器的自定义过滤器。
<TData>:QueryEngine 筛选的数据类型。
<TFilter>:筛选器比较的数据类型。
如果需要自行处理运算符,请使用此重载注册基本过滤器。
using System.Collections.Generic; using System.Linq; using UnityEditor; using UnityEditor.Search; using UnityEngine; static class Example_QueryEngine_AddFilter_Resolver { static List<MyObjectType> s_Data; [MenuItem("Examples/QueryEngine/AddFilter_Resolver")] public static void RunExample() { // Set up the query engine var queryEngine = new QueryEngine<MyObjectType>(); queryEngine.SetSearchDataCallback(myObj => new[] { myObj.id.ToString(), myObj.name }); // Add a custom filter "is", with a resolver that will handle all operators queryEngine.AddFilter<string>("is", (myObj, operatorToken, filterValue) => { if (operatorToken != ":") return false; switch (filterValue) { case "active": return myObj.active; case "root": return myObj.id == 0; case "center": return myObj.position == Vector2.zero; default: return false; } }, new[] {":"}); s_Data = new List<MyObjectType>() { new MyObjectType { id = 0, name = "Test 1", position = new Vector2(0, 0), active = false }, new MyObjectType { id = 1, name = "Test 2", position = new Vector2(0, 1), active = true }, new MyObjectType { id = 2, name = "Test 3", position = new Vector2(1, 0), active = false }, new MyObjectType { id = 3, name = "Test 4", position = new Vector2(1.2f, 0), active = false }, }; // Find all items that are of type "active" var query = queryEngine.ParseQuery("is:active"); var filteredData = query.Apply(s_Data).ToList(); Debug.Assert(filteredData.Count == 1, $"There should be 1 item in the filtered list but found {filteredData.Count} items."); Debug.Assert(filteredData.Contains(s_Data[1]), "Test 2 should be in the list as it is active."); // Find all items that are root query = queryEngine.ParseQuery("is:root"); filteredData = query.Apply(s_Data).ToList(); Debug.Assert(filteredData.Count == 1, $"There should be 1 item in the filtered list but found {filteredData.Count} items."); Debug.Assert(filteredData.Contains(s_Data[0]), "Test 1 should be in the list as it is a root."); } class MyObjectType { public int id { get; set; } public string name { get; set; } = string.Empty; public Vector2 position { get; set; } = Vector2.zero; public bool active { get; set; } public override string ToString() { return $"({id}, {name}, ({position.x}, {position.y}), {active})"; } } }
token | 筛选器的标识符。通常为筛选器中操作符前面的部分(例如,“id>=2”中的“id”)。 |
filterResolver | 用于处理此过滤器的任何运算符的回调。获取一个 TData 类型的对象、一个 TParam 类型的对象、运算符令牌和过滤器值,并返回一个布尔值指示过滤器是否已通过或未通过。 |
parameterTransformer | 用于将字符串转换成 TParam 类型的回调。解析查询时使用,将传递给函数的内容转换成正确的格式。 |
supportedOperatorType | 受支持的操作符令牌列表。此列表包含受支持的操作符令牌。将 null 或空列表与指示支持所有运算符相关联。 |
添加一个带参数和完整解析器的自定义过滤器。
<TData>:QueryEngine 筛选的数据类型。
<TFilter>:筛选器比较的数据类型。
<TParam>:传递给过滤器的的数据类型。
如果需要自行处理运算符,请使用此重载注册接受参数的过滤器。
using System.Collections.Generic; using System.Globalization; using System.Linq; using UnityEditor; using UnityEditor.Search; using UnityEngine; static class Example_QueryEngine_AddFilter_Param_Resolver { static List<MyObjectType> s_Data; [MenuItem("Examples/QueryEngine/AddFilter_Param_Resolver")] public static void RunExample() { // Set up the query engine var queryEngine = new QueryEngine<MyObjectType>(); queryEngine.SetSearchDataCallback(myObj => new[] { myObj.id.ToString(), myObj.name }); // Add a "dist" filter to filter items based on a specified distance from a position or from another item, and handle all operators queryEngine.AddFilter<Vector2, string>("dist", (myObj, paramPosition, operatorToken, filterValue) => { var distance = (myObj.position - paramPosition).magnitude; if (operatorToken == ":") { switch (filterValue) { case "near": return distance <= 10.0f; case "far": return distance > 10.0f; } return false; } var floatValue = float.Parse(filterValue, CultureInfo.InvariantCulture.NumberFormat); switch (operatorToken) { case "=": return distance == floatValue; case "!=": return distance != floatValue; case "<": return distance < floatValue; case "<=": return distance <= floatValue; case ">": return distance > floatValue; case ">=": return distance >= floatValue; } return false; }, paramStringValue => { // Transform the parameter from a string to a usable Vector2 // If the user specified a vector if (paramStringValue.StartsWith("[") && paramStringValue.EndsWith("]")) { paramStringValue = paramStringValue.Trim('[', ']'); var vectorTokens = paramStringValue.Split(','); var vectorValues = vectorTokens.Select(token => float.Parse(token, CultureInfo.InvariantCulture.NumberFormat)).ToList(); return new Vector2(vectorValues[0], vectorValues[1]); } // Treat the value as the name of an object var myObj = s_Data.Find(obj => obj.name == paramStringValue); return myObj.position; }); s_Data = new List<MyObjectType>() { new MyObjectType { id = 0, name = "Test 1", position = new Vector2(0, 0), active = false }, new MyObjectType { id = 1, name = "Test 2", position = new Vector2(0, 10), active = true }, new MyObjectType { id = 2, name = "Test 3", position = new Vector2(10, 0), active = false }, new MyObjectType { id = 3, name = "Test 4", position = new Vector2(12f, 0), active = false }, }; // Find all items that are "near" "Test 1", including "Test 1" var query = queryEngine.ParseQuery("dist(Test 1):near"); var filteredData = query.Apply(s_Data).ToList(); Debug.Assert(filteredData.Count == 3, $"There should be 3 items in the filtered list but found {filteredData.Count} items."); Debug.Assert(!filteredData.Contains(s_Data[3]), "Test 4 should not be in the list as it is far of Test 1."); // Find all items that are far of [0, 0] query = queryEngine.ParseQuery("dist([0, 0]):far"); filteredData = query.Apply(s_Data).ToList(); Debug.Assert(filteredData.Count == 1, $"There should be 1 item in the filtered list but found {filteredData.Count} items."); Debug.Assert(filteredData.Contains(s_Data[3]), "Test 4 should be in the list as it is far of [0, 0]."); } class MyObjectType { public int id { get; set; } public string name { get; set; } = string.Empty; public Vector2 position { get; set; } = Vector2.zero; public bool active { get; set; } public override string ToString() { return $"({id}, {name}, ({position.x}, {position.y}), {active})"; } } }
token | 与过滤器匹配的正则表达式。匹配过滤器中操作符之前的内容(例如,“id>=2” 中的“id”)。 |
getDataFunc | 用于获取过滤器中使用的对象的回调。获取一个 TData 类型的对象、一个表示已匹配的实际过滤器名称的字符串,并返回一个 TFilter 类型的对象。 |
supportedOperatorType | 受支持的操作符令牌列表。此列表包含受支持的操作符令牌。将 null 或空列表与指示支持所有运算符相关联。 |
stringComparison | 字符串比较选项。 |
IQueryEngineFilter 新过滤器。
用正则表达式添加一个新的自定义过滤器。
<TData>:QueryEngine 筛选的数据类型。
<TFilter>:筛选器比较的数据类型。
使用这个重载,如果你不需要亲自处理运算符,来注册匹配正则表达式的基本过滤器。
using System; using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions; using UnityEditor; using UnityEditor.Search; using UnityEngine; static class Example_QueryEngine_AddFilter_Regex { static List<MyObjectType> s_Data; [MenuItem("Examples/QueryEngine/AddFilter_Regex")] public static void RunExample() { // Set up the query engine var queryEngine = new QueryEngine<MyObjectType>(); queryEngine.SetSearchDataCallback(myObj => new[] { myObj.id.ToString(), myObj.name }); SetupPropertyHandlers(queryEngine); // Add a regular expression filter to filter generic properties // When adding a new regular expression filter, there needs to be a single capturing group to retrieve the // actual name of the filter that matched. queryEngine.AddFilter(new Regex("#([\\w.]+)"), (myObj, filterNameMatch) => { if (myObj.property.name == filterNameMatch) return myObj.property; return Property.invalid; }); s_Data = new List<MyObjectType>() { new MyObjectType { id = 0, property = new Property("size", PropertyType.Integer, 64) }, new MyObjectType { id = 1, property = new Property("size", PropertyType.Integer, 128) }, new MyObjectType { id = 2, property = new Property("tag", PropertyType.String, "item") }, new MyObjectType { id = 3, property = new Property("tag", PropertyType.String, "car item") } }; // Find all objects that have a property "size" greater than 32 var query = queryEngine.ParseQuery("#size>32"); var filteredData = query.Apply(s_Data).ToList(); Debug.Assert(filteredData.Count == 2, $"There should be 2 items in the filtered list but found {filteredData.Count} items."); Debug.Assert(filteredData.Contains(s_Data[0]), "Object 0 should be in the list as its property \"size\" is > 32."); Debug.Assert(filteredData.Contains(s_Data[1]), "Object 1 should be in the list as its property \"size\" is > 32."); // Find all objects that have a property "size" equal to 128 query = queryEngine.ParseQuery("#size=128"); filteredData = query.Apply(s_Data).ToList(); Debug.Assert(filteredData.Count == 1, $"There should be 1 item in the filtered list but found {filteredData.Count} items."); Debug.Assert(filteredData.Contains(s_Data[1]), "Object 1 should be in the list as its property \"size\" is = 128."); // Find all objects that have a property "tag" that contains "item" query = queryEngine.ParseQuery("#tag:item"); filteredData = query.Apply(s_Data).ToList(); Debug.Assert(filteredData.Count == 2, $"There should be 2 items in the filtered list but found {filteredData.Count} items."); Debug.Assert(filteredData.Contains(s_Data[2]), "Object 2 should be in the list as its property \"tag\" contains \"item\"."); Debug.Assert(filteredData.Contains(s_Data[3]), "Object 3 should be in the list as its property \"tag\" contains \"item\"."); } static void SetupPropertyHandlers(QueryEngine<MyObjectType> qe) { qe.AddOperatorHandler(":", (Property v, int number, StringComparison sc) => PropertyIntCompare(v, number, (f, r) => f.ToString().IndexOf(r.ToString()) != -1)); qe.AddOperatorHandler("=", (Property v, int number) => PropertyIntCompare(v, number, (f, r) => f == r)); qe.AddOperatorHandler("!=", (Property v, int number) => PropertyIntCompare(v, number, (f, r) => f != r)); qe.AddOperatorHandler("<=", (Property v, int number) => PropertyIntCompare(v, number, (f, r) => f <= r)); qe.AddOperatorHandler("<", (Property v, int number) => PropertyIntCompare(v, number, (f, r) => f < r)); qe.AddOperatorHandler(">", (Property v, int number) => PropertyIntCompare(v, number, (f, r) => f > r)); qe.AddOperatorHandler(">=", (Property v, int number) => PropertyIntCompare(v, number, (f, r) => f >= r)); qe.AddOperatorHandler(":", (Property v, string s, StringComparison sc) => PropertyStringCompare(v, s, (f, r) => f.IndexOf(r, sc) != -1)); qe.AddOperatorHandler("=", (Property v, string s, StringComparison sc) => PropertyStringCompare(v, s, (f, r) => string.Equals(f, r, sc))); qe.AddOperatorHandler("!=", (Property v, string s, StringComparison sc) => PropertyStringCompare(v, s, (f, r) => !string.Equals(f, r, sc))); qe.AddOperatorHandler("<=", (Property v, string s, StringComparison sc) => PropertyStringCompare(v, s, (f, r) => string.Compare(f, r, sc) <= 0)); qe.AddOperatorHandler("<", (Property v, string s, StringComparison sc) => PropertyStringCompare(v, s, (f, r) => string.Compare(f, r, sc) < 0)); qe.AddOperatorHandler(">", (Property v, string s, StringComparison sc) => PropertyStringCompare(v, s, (f, r) => string.Compare(f, r, sc) > 0)); qe.AddOperatorHandler(">=", (Property v, string s, StringComparison sc) => PropertyStringCompare(v, s, (f, r) => string.Compare(f, r, sc) >= 0)); } static bool PropertyStringCompare(Property p, string s, Func<string, string, bool> comparer) { if (p.type != PropertyType.String) return false; return comparer((string)p.value, s); } static bool PropertyIntCompare(Property p, int number, Func<int, int, bool> comparer) { if (p.type != PropertyType.Integer) return false; return comparer((int)p.value, number); } enum PropertyType { None, Integer, String, Integer_Array } struct Property { public string name { get; } public PropertyType type { get; } public object value { get; set; } public Property(string name, PropertyType type, object value) { this.name = name; this.type = type; this.value = value; } public static Property invalid = new Property(string.Empty, PropertyType.None, null); } class MyObjectType { public int id { get; set; } public string name { get; set; } = string.Empty; public Vector2 position { get; set; } = Vector2.zero; public bool active { get; set; } public Property property { get; set; } = Property.invalid; public override string ToString() { return $"({id}, {name}, ({position.x}, {position.y}), {active})"; } } }
token | 与过滤器匹配的正则表达式。匹配过滤器中操作符之前的内容(例如,“id>=2” 中的“id”)。 |
getDataFunc | 用于获取在过滤器中使用的对象的回调。获取类型为 TData 的对象,表示匹配的实际过滤器名称的字符串,类型为 TParam 的对象,并返回类型为 TFilter 的对象。 |
supportedOperatorType | 受支持的操作符令牌列表。此列表包含受支持的操作符令牌。将 null 或空列表与指示支持所有运算符相关联。 |
stringComparison | 字符串比较选项。 |
parameterTransformer | 用于将字符串转换成 TParam 类型的回调。解析查询时使用,将传递给函数的内容转换成正确的格式。 |
IQueryEngineFilter 新过滤器。
用正则表达式和参数添加一个新的自定义过滤器。
<TData>:QueryEngine 筛选的数据类型。
<TFilter>:筛选器比较的数据类型。
<TParam>:传递给过滤器的的数据类型。
使用这个重载,如果你不需要亲自处理运算符,来注册匹配正则表达式和接受参数的过滤器。
using System; using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions; using UnityEditor; using UnityEditor.Search; using UnityEngine; static class Example_QueryEngine_AddFilter_Param_Regex { static List<MyObjectType> s_Data; [MenuItem("Examples/QueryEngine/AddFilter_Param_Regex")] public static void RunExample() { // Set up the query engine var queryEngine = new QueryEngine<MyObjectType>(); queryEngine.SetSearchDataCallback(myObj => new[] { myObj.id.ToString(), myObj.name }); SetupPropertyHandlers(queryEngine); // Add a regular expression filter function to filter generic properties with parameters // When adding a new regular expression filter, there needs to be a single capturing group to retrieve the // actual name of the filter that matched. queryEngine.AddFilter<int, Property>(new Regex("\\$([\\w.]+)"), (myObj, filterNameMatch, param) => { if (myObj.property.name != filterNameMatch) return Property.invalid; if (myObj.property.type != PropertyType.Integer_Array) return Property.invalid; if (!(myObj.property.value is int[] array)) return Property.invalid; if (param < 0 || param >= array.Length) return Property.invalid; return new Property(myObj.property.name, PropertyType.Integer, array[param]); }); s_Data = new List<MyObjectType>() { new MyObjectType { id = 0, property = new Property("size", PropertyType.Integer, 64) }, new MyObjectType { id = 1, property = new Property("size", PropertyType.Integer, 128) }, new MyObjectType { id = 2, property = new Property("tag", PropertyType.String, "item") }, new MyObjectType { id = 3, property = new Property("tag", PropertyType.String, "car item") }, new MyObjectType { id = 4, property = new Property("values", PropertyType.Integer_Array, new int[] {0, 2, 42}) }, new MyObjectType { id = 5, property = new Property("values", PropertyType.Integer_Array, new int[] {8, 52, 210}) }, new MyObjectType { id = 6, property = new Property("weights", PropertyType.Integer_Array, new int[] {1000, 250, 400}) } }; // Find all objects that have a property "values" with a sub value greater than 42 at index 1 var query = queryEngine.ParseQuery("$values(1)>42"); var filteredData = query.Apply(s_Data).ToList(); Debug.Assert(filteredData.Count == 1, $"There should be 1 item in the filtered list but found {filteredData.Count} items."); Debug.Assert(filteredData.Contains(s_Data[5]), "Object 5 should be in the list as its property \"values\" at index 1 is > 42."); // Find all objects that have a property "weights" with a sub value lower or equal to 1000 at index 0 query = queryEngine.ParseQuery("$weights(0)<=1000"); filteredData = query.Apply(s_Data).ToList(); Debug.Assert(filteredData.Count == 1, $"There should be 1 item in the filtered list but found {filteredData.Count} items."); Debug.Assert(filteredData.Contains(s_Data[6]), "Object 6 should be in the list as its property \"weights\" at index 0 is <= 1000."); } static void SetupPropertyHandlers(QueryEngine<MyObjectType> qe) { qe.AddOperatorHandler(":", (Property v, int number, StringComparison sc) => PropertyIntCompare(v, number, (f, r) => f.ToString().IndexOf(r.ToString()) != -1)); qe.AddOperatorHandler("=", (Property v, int number) => PropertyIntCompare(v, number, (f, r) => f == r)); qe.AddOperatorHandler("!=", (Property v, int number) => PropertyIntCompare(v, number, (f, r) => f != r)); qe.AddOperatorHandler("<=", (Property v, int number) => PropertyIntCompare(v, number, (f, r) => f <= r)); qe.AddOperatorHandler("<", (Property v, int number) => PropertyIntCompare(v, number, (f, r) => f < r)); qe.AddOperatorHandler(">", (Property v, int number) => PropertyIntCompare(v, number, (f, r) => f > r)); qe.AddOperatorHandler(">=", (Property v, int number) => PropertyIntCompare(v, number, (f, r) => f >= r)); qe.AddOperatorHandler(":", (Property v, string s, StringComparison sc) => PropertyStringCompare(v, s, (f, r) => f.IndexOf(r, sc) != -1)); qe.AddOperatorHandler("=", (Property v, string s, StringComparison sc) => PropertyStringCompare(v, s, (f, r) => string.Equals(f, r, sc))); qe.AddOperatorHandler("!=", (Property v, string s, StringComparison sc) => PropertyStringCompare(v, s, (f, r) => !string.Equals(f, r, sc))); qe.AddOperatorHandler("<=", (Property v, string s, StringComparison sc) => PropertyStringCompare(v, s, (f, r) => string.Compare(f, r, sc) <= 0)); qe.AddOperatorHandler("<", (Property v, string s, StringComparison sc) => PropertyStringCompare(v, s, (f, r) => string.Compare(f, r, sc) < 0)); qe.AddOperatorHandler(">", (Property v, string s, StringComparison sc) => PropertyStringCompare(v, s, (f, r) => string.Compare(f, r, sc) > 0)); qe.AddOperatorHandler(">=", (Property v, string s, StringComparison sc) => PropertyStringCompare(v, s, (f, r) => string.Compare(f, r, sc) >= 0)); } static bool PropertyStringCompare(Property p, string s, Func<string, string, bool> comparer) { if (p.type != PropertyType.String) return false; return comparer((string)p.value, s); } static bool PropertyIntCompare(Property p, int number, Func<int, int, bool> comparer) { if (p.type != PropertyType.Integer) return false; return comparer((int)p.value, number); } enum PropertyType { None, Integer, String, Integer_Array } struct Property { public string name { get; } public PropertyType type { get; } public object value { get; set; } public Property(string name, PropertyType type, object value) { this.name = name; this.type = type; this.value = value; } public static Property invalid = new Property(string.Empty, PropertyType.None, null); } class MyObjectType { public int id { get; set; } public string name { get; set; } = string.Empty; public Vector2 position { get; set; } = Vector2.zero; public bool active { get; set; } public Property property { get; set; } = Property.invalid; public override string ToString() { return $"({id}, {name}, ({position.x}, {position.y}), {active})"; } } }
token | 与过滤器匹配的正则表达式。匹配过滤器中操作符之前的内容(例如,“id>=2” 中的“id”)。 |
filterResolver | 用于处理该过滤器的任何运算符的回调。获取类型为 TData 的对象,表示匹配的实际过滤器名称的字符串,运算符令牌和过滤器值,并返回一个布尔值,表示过滤器是否通过。 |
supportedOperatorType | 受支持的操作符令牌列表。此列表包含受支持的操作符令牌。将 null 或空列表与指示支持所有运算符相关联。 |
IQueryEngineFilter 新过滤器。
用正则表达式和一个完整的解析器添加一个新的自定义过滤器。
<TData>:QueryEngine 筛选的数据类型。
<TFilter>:筛选器比较的数据类型。
使用这个重载,如果你需要亲自处理运算符,来注册匹配正则表达式的基本过滤器。
using System; using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions; using UnityEditor; using UnityEditor.Search; using UnityEngine; static class Example_QueryEngine_AddFilter_Resolver_Regex { static List<MyObjectType> s_Data; [MenuItem("Examples/QueryEngine/AddFilter_Resolver_Regex")] public static void RunExample() { // Set up the query engine var queryEngine = new QueryEngine<MyObjectType>(); queryEngine.SetSearchDataCallback(myObj => new[] { myObj.id.ToString(), myObj.name }); SetupPropertyHandlers(queryEngine); // Add a regular expression filter to filter generic properties, with a resolver to handle all operators yourself. // When adding a new regular expression filter, there needs to be a single capturing group to retrieve the // actual name of the filter that matched. queryEngine.AddFilter<string>(new Regex("p_([\\w]+)"), (myObj, filterNameMatch, operatorToken, filterValue) => { if (operatorToken != ":") return false; if (myObj.property.name != filterNameMatch) return false; switch (filterValue) { case "enabled": return myObj.property.enabled; case "empty": { if (myObj.property.type != PropertyType.Integer_Array) return false; if (!(myObj.property.value is int[] array)) return false; return array.Length == 0; } default: return false; } }, new[] {":"}); s_Data = new List<MyObjectType>() { new MyObjectType { id = 0, property = new Property("size", PropertyType.Integer, 64, true) }, new MyObjectType { id = 1, property = new Property("size", PropertyType.Integer, 128, false) }, new MyObjectType { id = 2, property = new Property("tag", PropertyType.String, "item", true) }, new MyObjectType { id = 3, property = new Property("tag", PropertyType.String, "car item", false) }, new MyObjectType { id = 4, property = new Property("values", PropertyType.Integer_Array, new int[] {0, 2, 42}, true) }, new MyObjectType { id = 5, property = new Property("values", PropertyType.Integer_Array, new int[] {8, 52, 210}, false) }, new MyObjectType { id = 6, property = new Property("weights", PropertyType.Integer_Array, new int[] {1000, 250, 400}, false) }, new MyObjectType { id = 7, property = new Property("weights", PropertyType.Integer_Array, new int[] {}, false) } }; // Find all items that have a property "size" that is enabled. var query = queryEngine.ParseQuery("p_size:enabled"); var filteredData = query.Apply(s_Data).ToList(); Debug.Assert(filteredData.Count == 1, $"There should be 1 item in the filtered list but found {filteredData.Count} items."); Debug.Assert(filteredData.Contains(s_Data[0]), "Object 0 should be in the list as its property \"size\" is enabled."); // Find all items that have a property "weights" that is empty. query = queryEngine.ParseQuery("p_weights:empty"); filteredData = query.Apply(s_Data).ToList(); Debug.Assert(filteredData.Count == 1, $"There should be 1 item in the filtered list but found {filteredData.Count} items."); Debug.Assert(filteredData.Contains(s_Data[7]), "Object 7 should be in the list as its property \"weights\" is empty."); } static void SetupPropertyHandlers(QueryEngine<MyObjectType> qe) { qe.AddOperatorHandler(":", (Property v, int number, StringComparison sc) => PropertyIntCompare(v, number, (f, r) => f.ToString().IndexOf(r.ToString()) != -1)); qe.AddOperatorHandler("=", (Property v, int number) => PropertyIntCompare(v, number, (f, r) => f == r)); qe.AddOperatorHandler("!=", (Property v, int number) => PropertyIntCompare(v, number, (f, r) => f != r)); qe.AddOperatorHandler("<=", (Property v, int number) => PropertyIntCompare(v, number, (f, r) => f <= r)); qe.AddOperatorHandler("<", (Property v, int number) => PropertyIntCompare(v, number, (f, r) => f < r)); qe.AddOperatorHandler(">", (Property v, int number) => PropertyIntCompare(v, number, (f, r) => f > r)); qe.AddOperatorHandler(">=", (Property v, int number) => PropertyIntCompare(v, number, (f, r) => f >= r)); qe.AddOperatorHandler(":", (Property v, string s, StringComparison sc) => PropertyStringCompare(v, s, (f, r) => f.IndexOf(r, sc) != -1)); qe.AddOperatorHandler("=", (Property v, string s, StringComparison sc) => PropertyStringCompare(v, s, (f, r) => string.Equals(f, r, sc))); qe.AddOperatorHandler("!=", (Property v, string s, StringComparison sc) => PropertyStringCompare(v, s, (f, r) => !string.Equals(f, r, sc))); qe.AddOperatorHandler("<=", (Property v, string s, StringComparison sc) => PropertyStringCompare(v, s, (f, r) => string.Compare(f, r, sc) <= 0)); qe.AddOperatorHandler("<", (Property v, string s, StringComparison sc) => PropertyStringCompare(v, s, (f, r) => string.Compare(f, r, sc) < 0)); qe.AddOperatorHandler(">", (Property v, string s, StringComparison sc) => PropertyStringCompare(v, s, (f, r) => string.Compare(f, r, sc) > 0)); qe.AddOperatorHandler(">=", (Property v, string s, StringComparison sc) => PropertyStringCompare(v, s, (f, r) => string.Compare(f, r, sc) >= 0)); } static bool PropertyStringCompare(Property p, string s, Func<string, string, bool> comparer) { if (p.type != PropertyType.String) return false; return comparer((string)p.value, s); } static bool PropertyIntCompare(Property p, int number, Func<int, int, bool> comparer) { if (p.type != PropertyType.Integer) return false; return comparer((int)p.value, number); } enum PropertyType { None, Integer, String, Integer_Array } struct Property { public string name { get; } public PropertyType type { get; } public object value { get; set; } public bool enabled { get; set; } public Property(string name, PropertyType type, object value, bool enabled) { this.name = name; this.type = type; this.value = value; this.enabled = enabled; } public static Property invalid = new Property(string.Empty, PropertyType.None, null, false); } class MyObjectType { public int id { get; set; } public string name { get; set; } = string.Empty; public Vector2 position { get; set; } = Vector2.zero; public bool active { get; set; } public Property property { get; set; } = Property.invalid; public override string ToString() { return $"({id}, {name}, ({position.x}, {position.y}), {active})"; } } }
token | 与过滤器匹配的正则表达式。匹配过滤器中操作符之前的内容(例如,“id>=2” 中的“id”)。 |
filterResolver | 用于处理此筛选器的任何运算符的回调。获取 TData 类型的对象、表示已匹配的实际筛选器名称的字符串、TParam 类型的对象、运算符令牌和筛选器值,并返回一个布尔值,指示筛选器是否通过。 |
supportedOperatorType | 受支持的操作符令牌列表。此列表包含受支持的操作符令牌。将 null 或空列表与指示支持所有运算符相关联。 |
parameterTransformer | 用于将字符串转换成 TParam 类型的回调。解析查询时使用,将传递给函数的内容转换成正确的格式。 |
IQueryEngineFilter 新过滤器。
使用正则表达式、参数和完整解析器添加新的自定义筛选器。
<TData>:QueryEngine 筛选的数据类型。
<TFilter>:筛选器比较的数据类型。
<TParam>:传递给过滤器的的数据类型。
如果您需要自己处理运算符,则可以使用此重载来注册与正则表达式匹配并接受参数的筛选器。
using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Text.RegularExpressions; using UnityEditor; using UnityEditor.Search; using UnityEngine; static class Example_QueryEngine_AddFilter_Param_Resolver_Regex { static List<MyObjectType> s_Data; [MenuItem("Examples/QueryEngine/AddFilter_Param_Resolver_Regex")] public static void RunExample() { // Set up the query engine var queryEngine = new QueryEngine<MyObjectType>(); queryEngine.SetSearchDataCallback(myObj => new[] { myObj.id.ToString(), myObj.name }); // Add a regular expression filter to filter generic properties, with a resolver to handle all operators yourself. // When adding a new regular expression filter, there needs to be a single capturing group to retrieve the // actual name of the filter that matched. queryEngine.AddFilter<int, string>(new Regex("p_([\\w]+)"), (myObj, filterNameMatch, index, operatorToken, filterValue) => { if (myObj.property.name != filterNameMatch) return false; if (myObj.property.type != PropertyType.Integer_Array) return false; if (!(myObj.property.value is int[] array)) return false; if (operatorToken == ":") { switch (filterValue) { case "valid": return index >= 0 && index < array.Length; default: return false; } } if (index < 0 || index >= array.Length) return false; var value = array[index]; var integerValue = int.Parse(filterValue, CultureInfo.InvariantCulture.NumberFormat); switch (operatorToken) { case "=": return value == integerValue; case "!=": return value != integerValue; case "<": return value < integerValue; case "<=": return value <= integerValue; case ">": return value > integerValue; case ">=": return value >= integerValue; } return false; }); s_Data = new List<MyObjectType>() { new MyObjectType { id = 0, property = new Property("size", PropertyType.Integer, 64, true) }, new MyObjectType { id = 1, property = new Property("size", PropertyType.Integer, 128, false) }, new MyObjectType { id = 2, property = new Property("tag", PropertyType.String, "item", true) }, new MyObjectType { id = 3, property = new Property("tag", PropertyType.String, "car item", false) }, new MyObjectType { id = 4, property = new Property("values", PropertyType.Integer_Array, new int[] {0, 2, 42}, true) }, new MyObjectType { id = 5, property = new Property("values", PropertyType.Integer_Array, new int[] {8, 52, 210}, false) }, new MyObjectType { id = 6, property = new Property("weights", PropertyType.Integer_Array, new int[] {1000, 250, 400}, false) }, new MyObjectType { id = 7, property = new Property("weights", PropertyType.Integer_Array, new int[] {}, false) } }; // Find all items that have a property named "weights" with a valid value at index 2. var query = queryEngine.ParseQuery("p_weights(2):valid"); var filteredData = query.Apply(s_Data).ToList(); Debug.Assert(filteredData.Count == 1, $"There should be 1 item in the filtered list but found {filteredData.Count} items."); Debug.Assert(filteredData.Contains(s_Data[6]), "Object 6 should be in the list as its property \"weights\" has a valid value at index 2."); // Find all items that have a property named "values" with a value greater than 50 at index 1. query = queryEngine.ParseQuery("p_values(1)>50"); filteredData = query.Apply(s_Data).ToList(); Debug.Assert(filteredData.Count == 1, $"There should be 1 item in the filtered list but found {filteredData.Count} items."); Debug.Assert(filteredData.Contains(s_Data[5]), "Object 5 should be in the list as its property \"values\" has a value > 50 at index 1."); } static void SetupPropertyHandlers(QueryEngine<MyObjectType> qe) { qe.AddOperatorHandler(":", (Property v, int number, StringComparison sc) => PropertyIntCompare(v, number, (f, r) => f.ToString().IndexOf(r.ToString()) != -1)); qe.AddOperatorHandler("=", (Property v, int number) => PropertyIntCompare(v, number, (f, r) => f == r)); qe.AddOperatorHandler("!=", (Property v, int number) => PropertyIntCompare(v, number, (f, r) => f != r)); qe.AddOperatorHandler("<=", (Property v, int number) => PropertyIntCompare(v, number, (f, r) => f <= r)); qe.AddOperatorHandler("<", (Property v, int number) => PropertyIntCompare(v, number, (f, r) => f < r)); qe.AddOperatorHandler(">", (Property v, int number) => PropertyIntCompare(v, number, (f, r) => f > r)); qe.AddOperatorHandler(">=", (Property v, int number) => PropertyIntCompare(v, number, (f, r) => f >= r)); qe.AddOperatorHandler(":", (Property v, string s, StringComparison sc) => PropertyStringCompare(v, s, (f, r) => f.IndexOf(r, sc) != -1)); qe.AddOperatorHandler("=", (Property v, string s, StringComparison sc) => PropertyStringCompare(v, s, (f, r) => string.Equals(f, r, sc))); qe.AddOperatorHandler("!=", (Property v, string s, StringComparison sc) => PropertyStringCompare(v, s, (f, r) => !string.Equals(f, r, sc))); qe.AddOperatorHandler("<=", (Property v, string s, StringComparison sc) => PropertyStringCompare(v, s, (f, r) => string.Compare(f, r, sc) <= 0)); qe.AddOperatorHandler("<", (Property v, string s, StringComparison sc) => PropertyStringCompare(v, s, (f, r) => string.Compare(f, r, sc) < 0)); qe.AddOperatorHandler(">", (Property v, string s, StringComparison sc) => PropertyStringCompare(v, s, (f, r) => string.Compare(f, r, sc) > 0)); qe.AddOperatorHandler(">=", (Property v, string s, StringComparison sc) => PropertyStringCompare(v, s, (f, r) => string.Compare(f, r, sc) >= 0)); } static bool PropertyStringCompare(Property p, string s, Func<string, string, bool> comparer) { if (p.type != PropertyType.String) return false; return comparer((string)p.value, s); } static bool PropertyIntCompare(Property p, int number, Func<int, int, bool> comparer) { if (p.type != PropertyType.Integer) return false; return comparer((int)p.value, number); } enum PropertyType { None, Integer, String, Integer_Array } struct Property { public string name { get; } public PropertyType type { get; } public object value { get; set; } public bool enabled { get; set; } public Property(string name, PropertyType type, object value, bool enabled) { this.name = name; this.type = type; this.value = value; this.enabled = enabled; } public static Property invalid = new Property(string.Empty, PropertyType.None, null, false); } class MyObjectType { public int id { get; set; } public string name { get; set; } = string.Empty; public Vector2 position { get; set; } = Vector2.zero; public bool active { get; set; } public Property property { get; set; } = Property.invalid; public override string ToString() { return $"({id}, {name}, ({position.x}, {position.y}), {active})"; } } }