2

是否有直接的方法(可能使用 REGEXP_REPLACE 等)来编辑出现在自由文本中的除最后四位数字(或长度为 5 或以上)之外的所有数字(文本中可能多次出现单独的数字)?

例如

Input = 'This is a test text with numbers 12345, 9876543210 and separately number 1234567887654321 all buried within the text'

Output = 'This is a test text with numbers ****5, *****3210 and separately number ************4321 all buried within the text'

使用 REGEX_REPLACE,用 * 替换所有数字显然很简单,但它会保留最后四位数字并用正确数量的 * 替换,这让我很烦恼。

任何帮助将非常感激!

(只是为了上下文,由于通常的业务限制,这必须在检索数据的查询中完成,而不是使用实际的 Oracle DBMS 编辑功能)。

非常感谢。

4

2 回答 2

3

您可以尝试以下正则表达式:

regexp_replace(txt, '(\d{4})(\d+(\D|$))', '****\2')

这将捕获 4 位数字的序列,后跟至少一个数字,然后是一个非数字字符(或字符串的结尾),并将它们替换为 4 颗星。

DB Fiddle 上的演示

with t as (select 'select This is a test text with numbers 12345, 9876543210 and separately number 1234567887654321 all buried within the text' txt from dual)
select regexp_replace(txt, '(\d{4})(\d+\D)', '****\2') new_text from t
| 新文本 |
| :------------------------------------------------ -------------------------------------------------- ------------------------------------ |
| 选择这是一个测试文本,数字****5、****543210 和单独的数字****567887654321 都埋在文本中 |

编辑

这是 Aleksej 在评论中建议的简化版本:

regexp_replace(txt, '(\d{4})(\d+)', '****\2')

这是因为正则表达式引擎的贪婪,它会尽可能多地吞下 '\d+'。

于 2019-10-31T09:56:12.043 回答
2

如果你真的需要保持数字的长度,那么(我认为)一步完成是没有办法的。您必须将字符串拆分为数字而不是数字,然后单独替换数字:

SELECT listagg(CASE WHEN REGEXP_LIKE(txt, '\d{5,}') -- if the string is of your desired format
                    THEN LPAD('*', LENGTH(txt) - 4,'*') || SUBSTR(txt, LENGTH(txt) -3) -- replace all digits but the last 4 with *
                    ELSE txt END)
       within GROUP (ORDER BY lvl)
  FROM (SELECT LEVEL lvl, REGEXP_SUBSTR(txt, '(\d+|\D+)', 1, LEVEL ) txt -- Split the string in numerical and non numerical parts 
          FROM (select 'This is a test text with numbers 12345, 9876543210 and separately number 1234567887654321 all buried within the text' AS  txt FROM dual)
       CONNECT BY REGEXP_SUBSTR(txt, '(\d+|\D+)', 1, LEVEL ) IS NOT NULL)

结果:

This is a test text with numbers *2345, ******3210 and separately number ************4321 all buried within the text

正如您的示例替换了第一个数字的第一个数字 - 您可能还想替换至少 4 位数字:

SELECT listagg(CASE WHEN REGEXP_LIKE(txt, '\d{5,}') -- if the string is of your desired format
                    THEN LPAD('*', GREATEST(LENGTH(txt) - 4, 4),'*') || SUBSTR(txt, GREATEST(LENGTH(txt) -3, 5)) -- replace all digits but the last 4 with *
                    ELSE txt END)
       within GROUP (ORDER BY lvl)
  FROM (SELECT LEVEL lvl, REGEXP_SUBSTR(txt, '(\d+|\D+)', 1, LEVEL ) txt -- Split the string in numerical and non numerical parts 
          FROM (select 'This is a test text with numbers 12345, 9876543210 and separately number 1234567887654321 all buried within the text' AS  txt FROM dual)
       CONNECT BY REGEXP_SUBSTR(txt, '(\d+|\D+)', 1, LEVEL ) IS NOT NULL)

(添加GREATEST到第二行以替换至少 4 位数字。)

结果:

This is a test text with numbers ****5, ******3210 and separately number ************4321 all buried within the text
于 2019-10-31T10:21:29.807 回答