我想在我的csv
文件中添加一列,其中包含随机创建的“案例编号”。案例编号的前 2 个字母必须是 AZ 中的任意大写字母。接下来是 5 个随机数。
输入:
COMPANY,NAME,STREET,ZIP,CITY,IBAN
Test Ltd,John,Big Ben 343,4343,London,UK2348020384
Test Ltd,Kate,Big Ben 343,4343,London,UK4389223892
Test Ltd,Jake,Big Ben 343,4343,London,UK3892898999
输出
COMPANY,NAME,STREET,ZIP,CITY,IBAN,CASENUMBER
Test Ltd,John,Big Ben 343,4343,London,UK2348020384,IN84903
Test Ltd,Kate,Big Ben 343,4343,London,UK4389223892,TY93842
Test Ltd,Jake,Big Ben 343,4343,London,UK3892898999,OL34307
如何与米勒一起做到这一点?我准备好了以下命令
mlr -I --csv put '${CASENUMBER}=xxx' then \
reorder -f COMPANY,NAME,STREET,ZIP,CITY,IBAN,CASENUMBER input/input.csv
到底要在上面的命令中添加什么?
答案1
这不使用 Miller(主要是因为我找不到一种方便的方法来处理随机字符),而是使用 GNU Awk:
awk -i ord -v OFS=, '
function randint(n) { return int(n*rand()) }
BEGIN { srand(); A = ord("A"); Z = ord("Z") }
NR == 1 { printf("%s,CASENUMBER\n", $0); next }
{ printf "%s,%c%c%.5d\n", $0, A + randint(Z-A+1), A + randint(Z-A+1), randint(100000) }' file.csv
这个 GNU Awk 命令拉入ord()
函数从ord.awk
图书馆(与 GNU Awk 一起分发)能够在字符及其 ASCII 表示形式之间进行转换。然后,为了方便起见,它会初始化随机数生成器srand()
并预先计算字母的 ASCII 值。A
Z
如果当前记录是第一的记录(即,它是 CSV 标头),它会输出附加的字符串,CASENUMBER
。
对于所有其他记录,它输出原始记录并在逗号后附加字符串。该字符串被计算为两个字符和一个零填充的数字。这两个字符是从范围中选取的[A,Z]
,数字也是从范围中选取的[0,100000)
。从范围中随机选取整数是使用该randint()
函数完成的,我正在使用未修改的函数来自 GNU Awk 手册。
对给定数据运行此命令的示例输出:
COMPANY,NAME,STREET,ZIP,CITY,IBAN,CASENUMBER
Test Ltd,John,Big Ben 343,4343,London,UK2348020384,HP88271
Test Ltd,Kate,Big Ben 343,4343,London,UK4389223892,XS17910
Test Ltd,Jake,Big Ben 343,4343,London,UK3892898999,UX00409
请注意,只要我们假设没有字段包含嵌入的换行符,我们实际上不需要解析输入数据。有了这个假设,只需将新数据附加到每行的末尾就足够了。
terdon在评论中指出确保计算出的案例 ID 是唯一的可能是一个好主意。这是通过在名为 的关联数组中跟踪已生成的 ID 来实现的seen
:
awk -i ord -v OFS=, '
function randint(n) { return int(n*rand()) }
function randid() { return sprintf("%c%c%.5d", A + randint(Z-A+1), A + randint(Z-A+1), randint(100000)) }
BEGIN { srand(); A = ord("A"); Z = ord("Z") }
NR == 1 { printf("%s,CASENUMBER\n", $0); next }
{
id = randid()
while (seen[id]++ > 0) id = randid()
printf "%s,%s\n", $0, id
}' file.csv
我还将随机案例 ID 的创建移到了它自己的函数中,因为我们需要从代码的主要部分调用它两次。
答案2
和perl
:
perl -lpe '$_ .= $. == 1 ? ",CASENUMBER" : sprintf ",%s%s%05d", ("A".."Z")[rand 26,rand 26], rand 1e5'
假设 CSV 字段不包含换行符。如果可以的话,您可以使用 perl 的Text::CSV
模块像 miller 那样进行正确的 CSV 解析和格式化。
答案3
米勒的一种方法。
alphabet="[\"A\", \"B\", \"C\", \"D\", \"E\", \"F\", \"G\", \"H\", \"I\", \"J\", \"K\", \"L\", \"M\", \"N\", \"O\", \"P\", \"Q\", \"R\", \"S\", \"T\", \"U\", \"V\", \"W\", \"X\", \"Y\", \"Z\"]"
mlr --csv put '$CASENUMBER=urandelement('"$alphabet"').urandelement('"$alphabet"').substr0(urand32(),0,5)' input.csv
你将会拥有
公司 | 姓名 | 街道 | 压缩 | 城市 | 国际银行账号 | 案件编号 |
---|---|---|---|---|---|---|
测试有限公司 | 约翰 | 大笨钟 343 | 4343 | 伦敦 | UK2348020384 | BV134526 |
测试有限公司 | 凯特 | 大笨钟 343 | 4343 | 伦敦 | UK4389223892 | ZF321045 |
测试有限公司 | 杰克 | 大笨钟 343 | 4343 | 伦敦 | 英国3892898999 | VQ302039 |
答案4
使用任何 awk:
$ cat tst.sh
#!/usr/bin/env bash
[[ -s /dev/urandom ]] && seed="$(od -An -N4 -tu4 /dev/urandom)"
awk -v seed="$seed" '
BEGIN {
if (seed) srand(seed); else srand()
FS = OFS = ","
chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
numChars = length(chars)
for ( i=1; i<=numChars; i++ ) {
for ( j=1; j<=numChars; j++ ) {
strs[++numStrs] = substr(chars,i,1) substr(chars,j,1)
}
}
numDigitCols = 5
numNumbers = length("0123456789") ^ numDigitCols
maxUnqAttempts = 100
}
{
for ( attempts=1; attempts<=maxUnqAttempts; attempts++ ) {
id = sprintf( "%s%05g", strs[int(1+rand()*numStrs)], int(rand()*numNumbers) )
if ( !seen[id]++ ) {
break
}
}
if ( attempts > maxUnqAttempts ) {
printf "%s[%d]: Failed to generate a unique ID after %d attempts, reusing %s\n", FILENAME, NR, maxUnqAttempts, id | "cat>&2"
}
print $0, (NR>1 ? id : "CASENUMBER")
}
' "${@:--}"
$ ./tst.sh input.csv
COMPANY,NAME,STREET,ZIP,CITY,IBAN,CASENUMBER
Test Ltd,John,Big Ben 343,4343,London,UK2348020384,TT93580
Test Ltd,Kate,Big Ben 343,4343,London,UK4389223892,MP70836
Test Ltd,Jake,Big Ben 343,4343,London,UK3892898999,TM77788