You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET中捕获表单数组值的正则表达式问题求助

解决自定义模型绑定器中表单数组值的解析问题

问题核心

你当前的实现把表单键值对直接拼接成扁平JSON,像"filterList[0].filterType"这种带索引的键无法被JSON反序列化器识别为数组结构,导致模型绑定失败。你尝试的正则表达式因未匹配开头的{和空格,漏过了第一个键值对。

不推荐正则的原因

正则处理结构化数据容易出现边界错误(比如值包含引号、特殊字符时匹配失效),且维护成本高。更可靠的方式是直接解析表单键的层级结构,构建正确的嵌套对象/数组。

结构化解析的解决方案

直接遍历表单键,拆分键的层级路径(比如filterList[0].filterType拆分为数组filterList的第0个元素的filterType属性),逐步构建对应的嵌套对象,最后直接映射到目标模型。

实现代码示例

private static async Task HandleFormAsync(HttpContext httpContext, ModelBindingContext bindingContext)
{
    var form = await httpContext.Request.ReadFormAsync();
    var modelObj = new JObject();

    foreach (var kvp in form)
    {
        var current = modelObj;
        var keyParts = SplitFormKey(kvp.Key);

        for (int i = 0; i < keyParts.Length; i++)
        {
            var part = keyParts[i];
            // 处理带索引的数组键,如filterList[0]
            if (part.Contains("["))
            {
                var arrayName = part.Split('[')[0];
                if (!int.TryParse(part.Split('[', ']')[1], out var index))
                {
                    bindingContext.Result = ModelBindingResult.Failed();
                    return;
                }

                // 确保数组存在,不存在则创建
                if (!current.TryGetValue(arrayName, out var arrayToken) || arrayToken.Type != JTokenType.Array)
                {
                    arrayToken = new JArray();
                    current[arrayName] = arrayToken;
                }

                var array = (JArray)arrayToken;
                // 确保数组元素数量足够,不足则补空对象
                while (array.Count <= index)
                {
                    array.Add(new JObject());
                }

                // 最后一个层级直接赋值,否则切换到数组元素继续处理
                if (i == keyParts.Length - 1)
                {
                    array[index] = JToken.FromObject(kvp.Value);
                }
                else
                {
                    current = (JObject)array[index];
                }
            }
            else
            {
                // 处理普通属性键
                if (i == keyParts.Length - 1)
                {
                    current[part] = JToken.FromObject(kvp.Value);
                }
                else
                {
                    // 确保对象存在,不存在则创建
                    if (!current.TryGetValue(part, out var objToken) || objToken.Type != JTokenType.Object)
                    {
                        objToken = new JObject();
                        current[part] = objToken;
                    }
                    current = (JObject)objToken;
                }
            }
        }
    }

    try
    {
        var model = modelObj.ToObject(bindingContext.ModelType);
        bindingContext.Result = ModelBindingResult.Success(model);
    }
    catch (JsonException)
    {
        bindingContext.Result = ModelBindingResult.Failed();
    }
}

// 安全拆分表单键,避免误拆数组括号内的字符
private static string[] SplitFormKey(string key)
{
    var parts = new List<string>();
    var currentPart = new StringBuilder();
    bool inBracket = false;

    foreach (var c in key)
    {
        if (c == '.' && !inBracket)
        {
            parts.Add(currentPart.ToString());
            currentPart.Clear();
        }
        else
        {
            if (c == '[') inBracket = true;
            if (c == ']') inBracket = false;
            currentPart.Append(c);
        }
    }

    parts.Add(currentPart.ToString());
    return parts.ToArray();
}

代码说明

  1. SplitFormKey方法:安全拆分表单键,确保数组括号内的字符不会被误拆分(比如list[0].item.name会被拆分为["list[0]", "item", "name"])。
  2. 嵌套结构构建:遍历拆分后的键层级,逐步创建数组、对象,将表单值赋值到对应位置,保证结构符合目标模型的要求。
  3. 直接映射模型:通过JObject.ToObject直接转换为目标模型类型,无需手动拼接JSON,避免格式错误。

正则表达式的临时修复(不推荐)

如果一定要用正则,调整表达式以匹配开头的{和空格:

(?:\{|\s|,)\s*"(?<arrayName>\w+\[\d+\])\.(?<propertyName>\w+)"\s*:\s*"(?<value>.*?)"\s*(?:,|})

但仍建议使用结构化解析方案,避免正则带来的各种边界问题。

内容的提问来源于stack exchange,提问作者ShanieMoonlight

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 12:44:53