如何筛选含指定允许字符及指定数量通配符的字符串行?
带通配符限制的字符串行筛选方案
需求明确
要从数据表筛选字符串行,满足两个核心条件:
- 字符串仅包含指定允许字符,最多可包含X个通配符(非允许字符)
- 通配符分两种场景:
- 单个通配符仅算一次:不管非允许字符种类,只要总个数≤X就行
- 单个通配符可无限复用:非允许字符的不同种类数≤X就行
- 举个例子:允许字符是
a、b、c,通配符数量0-2时,预期结果如下:
| id | value | 无通配符结果 | 1个通配符结果 | 2个通配符结果 |
|---|---|---|---|---|
| 1 | aabc | id1: aabc | id1: aabc | id1: aabc |
| 2 | aabcd | - | id2: aabcd | id2: aabcd |
| 3 | axbd | - | - | id3: axbd |
| 4 | cba | id4: cba | id4: cba | id4: cba |
场景1:非允许字符总个数≤X(单个通配符仅用一次)
这种场景用替换+长度统计最直观,比写复杂正则好扩展得多。
PostgreSQL实现代码
-- 允许字符:a/b/c,最多2个通配符 SELECT id, value FROM your_table -- 把所有允许字符替换为空,剩下的就是非允许字符,统计长度判断 WHERE length(REGEXP_REPLACE(value, '[abc]', '', 'gi')) <= 2;
- 扩展方式:直接把
[abc]改成你的允许字符集,<=2改成你要的X值即可,无需修改其他逻辑。
场景2:非允许字符种类数≤X(单个通配符可无限用)
这种需要统计有多少种不同的非允许字符,用CTE+数组去重来实现更清晰。
PostgreSQL实现代码
-- 允许字符:a/b/c,最多2种通配符 WITH non_allowed_stats AS ( SELECT id, value, -- 提取所有非允许字符,去重后转成数组 ARRAY( SELECT DISTINCT unnest(regexp_matches(value, '[^abc]', 'gi')) ) AS unique_non_allowed FROM your_table ) SELECT id, value FROM non_allowed_stats -- 数组长度就是不同非允许字符的数量,NULL表示没有非允许字符(符合0通配符要求) WHERE array_length(unique_non_allowed, 1) <= 2 OR array_length(unique_non_allowed, 1) IS NULL;
- 扩展方式:修改
[^abc]里的允许字符集,调整<=2的X值即可。
可扩展的正则方案(场景1)
如果偏好正则表达式,也可以写一个能灵活调整X的模式,避免硬编码多分支:
-- 允许字符a/b/c,最多2个通配符 SELECT * FROM your_table WHERE value ~* '^[abc]*([^abc][abc]*){0,2}$';
- 模式解释:开头是任意数量允许字符,然后是0到2次「一个非允许字符+任意数量允许字符」的组合,最后结尾,覆盖非允许字符在任意位置的情况。
- 扩展方式:把
{0,2}改成{0,X},替换[abc]为你的允许字符集即可。
原方案的问题
你之前写的正则^[abc -]*$|^[a-z][abc -]*$|^[abc -]*[a-z]$|^[abc -]*[a-z][abc -]*$存在两个明显问题:
- 分支重复冗余,要扩展到更大的X值需新增大量分支,完全不具备可扩展性
- 逻辑错误:用
[a-z]匹配通配符,实际应该匹配非允许字符,正确写法是[^abc]
内容的提问来源于stack exchange,提问作者xStoryTeller
相关产品推荐
相关产品推荐

