用****屏蔽输出卡号

Posted

技术标签:

【中文标题】用****屏蔽输出卡号【英文标题】:Mask output card number with **** 【发布时间】:2021-11-25 07:44:43 【问题描述】:

我的任务是在给定输入文件的情况下用星号 (*) 屏蔽每个信用卡号的前 12 位数字,并将屏蔽后的数字打印到输出文件中。

卡号示例:

1111-2222-3333-4444
4444-3333-2222-1111
1234-5678-9101-1171
1234 5678 9101 1121
7347_9834_7598_2834
8973#9858#3475#8734
2356`7843`0527`5340
8734=7583=4895=7007
8763+2430+6257_9406

一切都应该在 shell 脚本中完成

我的解决办法是:

#!/bin/bash

file='cards.txt'
while read data; do
echo $data | sed -r 's/[[:digit:]]4/****/;s/[[:digit:]]4/****/;s/[[:digit:]]4/****/;s/[^0-9,*]+/ /g'
done < $file > cards-masked.txt

关于如何在此任务中使用 sed 有什么更好的想法吗?

【问题讨论】:

【参考方案1】:

查看示例数据,您似乎总是有 4 个数字,由一个数字以外的字符分隔。

如果您也有兴趣使用 awk 解决方案,您可以先用空格替换除数字之外的所有字符。

然后将前 3 列中的所有字符替换为 *

awk 'gsub(/[^0-9]+/, " ");for (i=1;i<4;i++) gsub(/[0-9]/,"*",$i)1' cards.txt > cards-masked.txt

一个更易读的版本,带有简短的解释

awk '
  gsub(/[^0-9]+/, " ")                    # Replace all chars other than 0-9 with a space
  for (i=1;i<4;i++) gsub(/[0-9]/,"*",$i)  # Loop the first 3 columns, replace all digits with *
1' cards.txt > cards-masked.txt          # The 1 evaluates to true, printing the whole line

输出

**** **** **** 4444
**** **** **** 1111
**** **** **** 1171
**** **** **** 1121
**** **** **** 2834
**** **** **** 8734
**** **** **** 5340
**** **** **** 7007
**** **** **** 9406

【讨论】:

【参考方案2】:

第一个解决方案: 使用简单的sed 执行 3 次 4 位数字替换为 4 * 每次都设置好了。

sed -E 's/[[:digit:]]4/****/;s/[[:digit:]]4/****/;s/[[:digit:]]4/****/' Input_file


第二个解决方案: 使用awk 程序,只需使用3 次sub(substitute) 函数即可完成。

awk 'sub(/[[:digit:]]4/,"****");sub(/[[:digit:]]4/,"****");sub(/[[:digit:]]4/,"****") 1' Input_file

【讨论】:

我做的和你写的一模一样!但最后添加了;s/[^0-9,*]+/ /g 以删除任何符号,所以它看起来像**** **** **** nnnn【参考方案3】:

如果您的输入总是在每个第 4 位数字之后有一个非数字分隔符,那么使用gnu-awk,您可以使用RSRT 轻松完成。

使用-v RS='[^0-9]',我们将每条记录拆分为非数字字符,并使用模块将每条记录设置为****,当记录号不能被4整除时。最后使用ORS=RT,我们将捕获的非数字字符放在输出中,以获得与输入相同的分隔符。

awk -v RS='[^0-9]' 'NR%4 $0="****" ORS=RT 1' file > output

cat output

****-****-****-4444
****-****-****-1111
****-****-****-1171
**** **** **** 1121
****_****_****_2834
****#****#****#8734
****`****`****`5340
****=****=****=7007
****+****+****_9406

【讨论】:

【参考方案4】:

很简单:

cat cards.txt|rev|sed -e 's/[[:digit:]]/*/5g' |rev > cards-masked.txt

echo "1234-5678-9123-1234"|rev|sed -e 's/[[:digit:]]/*/5g' |rev
****-****-****-1234

这是反向任务:

cat cards.txt|sed -e 's/[[:digit:]]/*/13g' > cards-masked.txt

如您所见,while/read 循环也不需要。每一个 sed 表达式都会被逐行计算。

【讨论】:

谢谢。但是,如果我需要输出为:**** **** **** 1234 我们该怎么做呢? @arheops : 如果你去掉 cat 会更简单。 @isvalx : 1234 来自哪里?我无法从您的问题中理解这一点。 @isvalx 它会按照您的要求输出,只需测试它。【参考方案5】:

这可能对你有用(GNU sed):

sed -E '/([0-9]4[ #`=+-_])3[0-9]4/s//\n&\n/;h
       s/[0-9]/*/g;G;s/.*\n(.*)\n.*\n(.*)\n.*\n/\2\1/' file

用换行符包围匹配项。

复制一份。

将所有数字替换为*'s

附加副本。

使用模式匹配,将原始匹配替换为修改后的匹配。

可以扩展为一行中的多个匹配项:

sed -E ':a;/([0-9]4[ #`=+-_])3[0-9]4/s//\n&\n/;h
       s/[0-9]/*/g;G;s/.*\n(.*)\n.*\n(.*)\n.*\n/\2\1/;ta' file

要仅替换前九位,请使用:

sed -E ':a;/(([0-9]4[ #`=+-_])3)([0-9]4)/s//\n\1\n\3/;h
       s/[0-9]/*/g;G;s/.*\n(.*)\n.*\n(.*)\n.*\n/\2\1/;ta' file

【讨论】:

大声笑。这真的很简单。需要花……小时?了解这种简单性。 @arheops 或许可以看到here 但是如果与原始变体或我的变体相比,它有多简单?我知道有很多复杂的方法可以做到这一点。但是为什么? @arheops 这是一个通用解决方案,有望涵盖大多数边缘情况。当候选人来寻找类似的解决方案时,这可能是这些人的起点。【参考方案6】:

替换前 15 个字符:

sed -e 's/^.\15\/**** **** **** /' < file

输出:

**** **** **** 4444
…
**** **** **** 9406

相同,但将字符保留在位置 5、10 和 15:

sed -e 's/^....\(.\)....\(.\)....\(.\)/****\1****\2****\3/' < file

输出:

****-****-****-4444
…
****+****+****_9406

【讨论】:

以上是关于用****屏蔽输出卡号的主要内容,如果未能解决你的问题,请参考以下文章

使用 PySpark 屏蔽信用卡号

Paypal Vault 卡号被屏蔽

在 SQL Server 中屏蔽信用卡号

如何屏蔽信用卡号的前两个字母和后四个字母[关闭]

如何在.net中屏蔽信用卡号的前6位和后4位

C# Windows 应用程序(不是 wpf)将文本框中的信用卡号屏蔽为输入,然后验证和处理信用卡号