使用C#实现从Hive的CREATE TABLE语句中提取分区字段名和数据类型

csharp 复制代码
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;

namespace HivePartitionParser
{
    public class Program
    {
        private static readonly Regex PartitionedByRegex = new Regex(
            @"PARTITIONED\s+BY\s*\(([^)]*)\)",
            RegexOptions.IgnoreCase | RegexOptions.Compiled
        );

        private static readonly Regex FieldRegex = new Regex(
            @"^(?:`(?<name>[^`]+)`|(?<name>\w+))\s+(?<type>\w+(?:\([^)]*\)|<[^>]*>)?)",
            RegexOptions.ExplicitCapture | RegexOptions.Compiled
        );

        public static void Main(string[] args)
        {
            const string createTableSql = @"
                CREATE TABLE employees (
                    id INT,
                    name STRING
                )
                PARTITIONED BY (year INT, month STRING, salary DECIMAL(10,2))
                STORED AS ORC;";

            foreach (var (name, type) in ParsePartitionColumns(createTableSql))
            {
                Console.WriteLine($"Partition Column: {name.PadRight(15)} Type: {type}");
            }
        }

        public static IEnumerable<(string Name, string Type)> ParsePartitionColumns(string sql)
        {
            var partitionedByMatch = PartitionedByRegex.Match(sql);
            if (!partitionedByMatch.Success) yield break;

            var columnsText = partitionedByMatch.Groups[1].Value.Trim();
            foreach (var columnDef in SplitColumnDefinitions(columnsText))
            {
                var match = FieldRegex.Match(columnDef);
                if (match.Success)
                {
                    yield return (
                        match.Groups["name"].Value,
                        match.Groups["type"].Value
                    );
                }
            }
        }

        private static IEnumerable<string> SplitColumnDefinitions(string input)
        {
            int depth = 0, start = 0;
            for (int i = 0; i < input.Length; i++)
            {
                switch (input[i])
                {
                    case '(': depth++; break;
                    case ')': depth--; break;
                    case ',' when depth == 0:
                        yield return input.Substring(start, i - start).Trim();
                        start = i + 1;
                        break;
                }
            }
            if (start < input.Length)
                yield return input.Substring(start).Trim();
        }
    }
}

代码说明:

  1. 正则表达式优化:

    • 使用预编译正则表达式(RegexOptions.Compiled)提升匹配性能
    • PartitionedByRegex 用于定位分区定义部分
    • FieldRegex 用于解析字段名称和类型
  2. 核心解析逻辑:

    • 使用括号深度感知的分割算法处理嵌套结构
    • 支持处理带括号的复杂类型(如DECIMAL(10,2))
    • 支持反引号包裹的字段名
  3. 性能优化:

    • 避免不必要的字符串分配
    • 使用迭代器实现延迟处理
    • 减少中间集合的创建
  4. 关键方法:

    • ParsePartitionColumns:主解析方法
    • SplitColumnDefinitions:智能分割字段定义

示例输出:

复制代码
Partition Column: year            Type: INT
Partition Column: month           Type: STRING
Partition Column: salary          Type: DECIMAL(10,2)

该实现能够正确处理以下复杂场景:

  • 带括号的类型定义
  • 反引号包裹的字段名
  • 嵌套的复杂类型(如MAP<STRING,ARRAY>)
  • 各种空格格式(包括换行和多余空格)
相关推荐
死磕音视频4 小时前
让小模型做选择题:限定候选项并读取 logits 概率的入门实践(附 Python 代码)
开发语言·python·大模型·文本分类·transformers
省钱兄--zs6 小时前
深圳24小时自助健身房软硬件解决方案实战指南与开发流程详解
java·数据仓库·spring boot·小程序·架构
顽疲6 小时前
Java vue 养老系统源码详解:月账单 care_month_bill 与 Quartz 扣费 Job 实践
java·开发语言·vue.js·vue养老·springboot养老·java养老
Wang's Blog6 小时前
Java 项目实战: 交友项目 - 安装开发工具与环境准备
java·开发语言·交友
曹牧7 小时前
C#:输入的字符串格式不正确
c#
程序喵大人8 小时前
【C++入门】编译链接模型 - 07 链接器怎样把符号对上号
开发语言·c++·编译器·编译链接·链接器
微三云 - 廖会灵 (私域系统开发)8 小时前
供应链系统实战:多渠道订单聚合与分布式库存一致性方案总结
开发语言·分布式·php
学逆向的9 小时前
C 数据溢出与精度丢失
c语言·开发语言·网络安全
霸道流氓气质9 小时前
AgentFlow 入门与实战:Task-Based 并发、EWMA 动态调度与四道门禁的 Java 生产级编排
java·开发语言
释厄62310 小时前
错误无误公理——错误正确本同源都迭代定律——逆转有价值
android·开发语言·kotlin