我们有一个包含大量数据的大型数据库。我最近发现我们的销售和运输部门一直在使用应用程序的一部分来公开存储客户的信用卡号码。我们已经制止了它,但现在有数千行带有数字。
我们正试图弄清楚如何在某些列中连续扫描 16 位数字(或破折号分隔)并用 X 替换它们。
这不是一个简单的 UPDATE 语句,因为卡号存储在大量文本中。到目前为止,我一直无法弄清楚 SQL Server 是否能够使用正则表达式(似乎没有)。
其他一切都失败了,我将通过 PHP 做到这一点,因为那是我最擅长的……但这会很痛苦。
我们有一个包含大量数据的大型数据库。我最近发现我们的销售和运输部门一直在使用应用程序的一部分来公开存储客户的信用卡号码。我们已经制止了它,但现在有数千行带有数字。
我们正试图弄清楚如何在某些列中连续扫描 16 位数字(或破折号分隔)并用 X 替换它们。
这不是一个简单的 UPDATE 语句,因为卡号存储在大量文本中。到目前为止,我一直无法弄清楚 SQL Server 是否能够使用正则表达式(似乎没有)。
其他一切都失败了,我将通过 PHP 做到这一点,因为那是我最擅长的……但这会很痛苦。
听起来您需要将 PATINDEX 与 WHERE LIKE 子句一起使用。
像这样的东西。用类似的东西创建一个存储过程,然后用你已经确定的一堆不同的参数(使@pattern & @patternlength 成为参数)调用它,直到你替换了所有的实例。
declare @pattern varchar(100), @patternlength int
set @pattern = '[0-9][0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]'
set @patternlength = 19
update tableName
set fieldName =
LEFT(fieldName, patindex('%'+ @pattern + '%', fieldName)-1)
+ 'XXXX-XXXX-XXXX-XXXX'
+ SUBSTRING(fieldName, PATINDEX('%'+ @pattern + '%', fieldName)+@patternlength, LEN(fieldName))
from tableName
where fieldName like '%'+ @pattern + '%'
诀窍就是找到合适的模式,并设置合适的@patternlength 值(不是@pattern 的长度,因为那不起作用!)
我认为您最好以编程方式执行此操作,特别是因为您提到数据可以采用几种不同的格式。请记住,并非所有信用卡号都是 16 位长(Amex 是 15,Visa 是 13 或 16,等等)。
如果可能,最好在清理作业级别提供检查各种正则表达式和验证代码的能力。
我最近遇到了这种情况。使用 Patindex 和 Stuff 应该会有所帮助,但是您需要分别重复具有不同位数的 CC 号码。
-- For 16 digits CC numbers
UPDATE table
SET columnname = Stuff (columnname, Patindex(
'%[3-6][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]%'
, columnname), 16, '################')
WHERE Patindex(
'%[3-6][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]%'
, columnname) > 0
即兴肖恩的回答。
下面将在@text 中找到所有出现的@maskPattern 并将它们替换为'x'。例如,如果@maskPattern = XXXX-XXXX-XXXX-XXXX,它将在@text 中找到此模式并将所有出现的地方替换为 XXXX-XXXX-XXXX-XXXX。如果它没有找到任何匹配项,它将保持文本不变。
此存储过程也可以被操作为仅屏蔽 maskPattern 开头的 3/4。干杯!
ALTER PROCEDURE [dbo].[SP_MaskCharacters] @text nvarchar(max),
@maskPattern nvarchar(500)
AS
BEGIN
DECLARE @numPattern nvarchar(max) = REPLACE(@maskPattern, 'x', '[0-9]')
DECLARE @patternLength int = LEN(@maskPattern)
WHILE (@text IS NOT NULL)
BEGIN
IF PATINDEX('%' + @numPattern + '%', @text) = 0 BREAK;
SET @text =
LEFT(@text, PATINDEX('%' + @numPattern + '%', @text)-1) --Get beginning chars of the input text until first occurance of pattern is found
+ @maskPattern --Append aasking pattern
+ SUBSTRING(@text, PATINDEX('%' + @numPattern + '%', @text) + @patternLength, LEN(@text)) -- Get & append rest of the text found after masking attern
END
SELECT @text
END
您可以使用 patindex。它不会很漂亮,可能有更简洁的方式来编写它。但是您可以使用集合,即 [0-9]
patindex:http: //msdn.microsoft.com/en-us/library/ms188395.aspx
对于任何发现此问题但确实想使用 PHP 的人,这是我使用的一个函数,它接受信用卡号(所有数字,带有破折号或带有空格)并将除第一个和最后 4 位数字之外的所有数字替换为“X”。
要同时接受带有破折号的信用卡号,请改用此正则表达式模式:
$cc_regex_pattern = '/(\d{4})(-)?(\d{4})(-)?(\d{4})(-)?(\d{4})/'
并删除删除破折号的 cc 号码的预处理:
$compressed_cc_number = preg_replace('/(\ |-)/', '', $credit_card_number);
所以替换字符串变成了(因为我们改变了模式的索引——注意 $7):
$cc_regex_replacement = '$1' . $cc_middle_pattern . '$7';
或者,如果您愿意,只需替换整个 cc 编号,就像在原始问题中一样:
$cc_regex_replacement = 'XXXX$2XXXX$4XXXX$6XXXX';
这是带有或不带空格或破折号的信用卡号的原始功能,它混淆并删除了任何破折号:
/**
* @param integer|string $credit_card_number
* @return mixed
*/
static function obfuscate_credit_card($credit_card_number)
{
$compressed_cc_number = preg_replace('/(\ |-)/', '', $credit_card_number);
$cc_length = strlen($compressed_cc_number);
$cc_middle_length = $cc_length >= 9 ? $cc_length - 8 : 0;
//create middle pattern
$cc_middle_pattern = '';
for ($i = 0; $i < $cc_middle_length; $i++) {
$cc_middle_pattern .= 'X';
}
//replace cc middle digits with middle pattern
$cc_regex_pattern = '/(\d{4})(\d+)(\d{4})/';
$cc_regex_replacement = '$1' . $cc_middle_pattern . '$3';
$obfuscated_cc = preg_replace($cc_regex_pattern, $cc_regex_replacement, $compressed_cc_number);
return $obfuscated_cc;
}