Oracle SQL如何替换以ssn开头的不定长子串为同等长度星号
实现思路
你原有写法的问题有两个:
- 正则匹配规则错误,只匹配了
ssn后的非数字部分,没有覆盖到后续的整段数字内容 - 直接写
*作为替换值,只会输出单个星号,无法做到和匹配子串等长替换
首先明确匹配规则:我们需要匹配以ssn开头,到最后一个连续数字结束的所有内容,正则可以写为ssn[^0-9]*[0-9]+([^0-9]+[0-9]+)*,可以覆盖你所有测试场景里的ssn+分隔符+多段数字的格式。
Oracle原生regexp_replace不支持直接动态生成等长替换字符,以下给出两种常用实现方案:
方案1:自定义函数(兼容所有Oracle版本,性能更优)
先创建自定义替换函数:
CREATE OR REPLACE FUNCTION replace_ssn_to_star(p_input VARCHAR2) RETURN VARCHAR2 IS v_res VARCHAR2(4000) := p_input; v_match VARCHAR2(4000); v_start_pos NUMBER := 1; v_match_len NUMBER; BEGIN LOOP -- 查找下一个符合规则的ssn子串 v_match := REGEXP_SUBSTR(v_res, 'ssn[^0-9]*[0-9]+([^0-9]+[0-9]+)*', v_start_pos, 1); EXIT WHEN v_match IS NULL; v_match_len := LENGTH(v_match); -- 替换为等长* v_res := SUBSTR(v_res, 1, v_start_pos - 1) || RPAD('*', v_match_len, '*') || SUBSTR(v_res, v_start_pos + v_match_len); v_start_pos := v_start_pos + v_match_len; END LOOP; RETURN v_res; END; /
使用方式:
SELECT replace_ssn_to_star(你的字段名) AS output FROM 你的表名;
方案2:递归CTE(无需创建函数,适合Oracle 11gR2及以上版本)
WITH rec_cte AS ( SELECT 原始字段名 AS str, REGEXP_COUNT(原始字段名, 'ssn[^0-9]*[0-9]+([^0-9]+[0-9]+)*') AS total_match, 1 AS match_idx FROM 你的表名 UNION ALL SELECT -- 替换当前匹配到的ssn子串为等长* SUBSTR(str, 1, REGEXP_INSTR(str, 'ssn[^0-9]*[0-9]+([^0-9]+[0-9]+)*', 1, match_idx) - 1) || RPAD('*', LENGTH(REGEXP_SUBSTR(str, 'ssn[^0-9]*[0-9]+([^0-9]+[0-9]+)*', 1, match_idx)), '*') || SUBSTR(str, REGEXP_INSTR(str, 'ssn[^0-9]*[0-9]+([^0-9]+[0-9]+)*', 1, match_idx) + LENGTH(REGEXP_SUBSTR(str, 'ssn[^0-9]*[0-9]+([^0-9]+[0-9]+)*', 1, match_idx))), total_match, match_idx + 1 FROM rec_cte WHERE match_idx <= total_match ) SELECT str AS output FROM rec_cte WHERE match_idx > total_match;
两种方案都可以完全匹配你给出的所有测试用例,输出和预期完全一致。
内容的提问来源于stack exchange,提问作者EX08
相关产品推荐
相关产品推荐

