如何使用递归Regex从以逗号替代CROSS JOIN的SQL中提取表名?
用正则提取交叉连接的表名:递归 vs 非递归方案
先明确:你要的场景不一定非要用递归,但如果是为了练手递归模式,完全可以实现。以下分两种方案说明,均针对你给出的规范SQL场景:
一、不用递归的简单方案
核心思路:先锁定FROM之后到终止关键字(ON|WHERE|GROUP BY|LIMIT)之间的内容,再从中提取每个表的核心名称。
分步实现
先匹配出
FROM到终止关键字的区间:FROM\s+(.*?)(?=\s+(?:ON|WHERE|GROUP BY|LIMIT)\b)这个正则用正向预查
(?=...)终止匹配,捕获到的分组1就是所有表项的字符串(比如table_1 AS a, table_2 AS b)。对分组1的内容,再用下面的正则提取每个表名:
\b(\w+)\b(?:\s+(?:AS\s+)?\w+\b)?解释:
\b(\w+)\b:捕获表的真实名称(比如table_1)(?:\s+(?:AS\s+)?\w+\b)?:匹配可选的别名部分,不管是AS a还是直接a都能覆盖
合并成单正则(直接捕获所有表名)
如果想一步到位,开启全局匹配模式即可:
\b(\w+)\b(?:\s+(?:AS\s+)?\w+\b)?(?=(?:\s*,\s*\b\w+\b(?:\s+(?:AS\s+)?\w+\b)?)*\s+(?:ON|WHERE|GROUP BY|LIMIT)\b)
全局匹配后就能直接拿到所有表名的数组。
二、用递归模式的实现(练手专用)
递归在这里的作用是重复匹配「逗号+表项」的结构,适合理解正则递归的逻辑。以下是PCRE引擎支持的写法(Python需用regex库,PHP直接支持):
(?<=FROM\s)(?:\b(\w+)\b(?:\s+(?:AS\s+)?\w+\b)?(?:\s*,\s*(?R))?)+(?=\s+(?:ON|WHERE|GROUP BY|LIMIT)\b)
关键部分解释
(?<=FROM\s):正向预查,确保当前位置在FROM之后\b(\w+)\b:捕获表名核心(?:\s+(?:AS\s+)?\w+\b)?:匹配可选别名(?:\s*,\s*(?R))?:递归整个模式,匹配下一个逗号分隔的表项((?R)代表重复整个正则的逻辑)(?=\s+(?:ON|WHERE|GROUP BY|LIMIT)\b):匹配到终止关键字时停止
测试你给出的所有示例,这个正则都能准确捕获到table_1、table_2(三表场景会多捕获table_3)。
注意事项
- 这个正则只适用于格式完全规范的SQL,一旦出现表名带特殊字符(比如
my-table)、嵌套子查询、注释等情况,直接失效——这也是为什么专业SQL解析器(比如Python的sqlparse)才是生产环境的正确选择。 - 递归模式依赖正则引擎支持,JavaScript等引擎不支持
(?R),要注意使用场景。
内容的提问来源于stack exchange,提问作者user1780424
相关产品推荐
相关产品推荐

