我有200万行csv文件,其中我要做的是用csv文件中每行的第二列替换该字符串的唯一值,这些都填充了用户名。我下面的漫长过程确实有效,但确实需要一段时间。
它不需要进行哈希处理,但这似乎是下一个文件出现时没有差异的可靠方法。
我绝不是一个程序员,并且想知道我是否能够优化这个过程。虽然我知道最好的方法是使用某种脚本语言。
#!/bin/bash
#Enter Filename to Read
echo "Enter File Name"
read filename
#Extracts Usersnames from file
awk -F "\"*,\"*" '{print $2}' $filename > usernames.txt
#Hashes Usernames using SHA256
cat usernames.txt | while read line; do echo -n $line|openssl sha256 |sed 's/^.* //'; done > hashedusernames.txt
#Deletes usernames out of first file
cat hash.csv | cut -d, -f2 --complement > output.txt
#Pastes hashed usernames to end of first file
paste -d , output.txt hashedusernames.txt > output2.txt
#Moves everything back into place
awk -F "\"*,\"*" '{print $1","$4","$2","$3}' output2.txt > final.csv
示例文件,共有7列,但只显示3列
Time Username Size
2017-01-01T14:53.45,Poke.callum,12345
2016-01-01T13:42.56,Test.User,54312
2015-01-01T12:34.34,Another.User,54123
答案 0 :(得分:1)
你可以在几行中轻松地在Perl中完成这项工作。以下程序使用Crypt::Digest::SHA256,您需要从CPAN或您的操作系统存储库安装它。
程序假定来自DATA
部分的输入,我们通常在此处执行此操作以在mcve中包含示例数据。
use strict;
use warnings;
use Crypt::Digest::SHA256 'sha256_b64u';
while (my $line = <DATA>) {
# no need to chomp because we don't touch the last line
my @fields = split /,/, $line;
$fields[1] = sha256_b64u($fields[1]);
print join ',', @fields;
}
__DATA__
2017-01-01T14:53.45,Poke.callum,12345
2016-01-01T13:42.56,Test.User,54312
2015-01-01T12:34.34,Another.User,54123
打印以下输出。
2017-01-01T14:53.45,g8EPHWc3L1ln_lfRhq8elyOUgsiJm6BtTtb_GVt945s,12345
2016-01-01T13:42.56,jwXsws2dJq9h_R08zgSIPhufQHr8Au8_RmniTQbEKY4,54312
2015-01-01T12:34.34,mkrKXbM1ZiPiXSSnWYNo13CUyzMF5cdP2SxHGyO7rgQ,54123
要使其读取作为命令行参数提供的文件并写入具有.new
扩展名的新文件,您可以像这样使用它:
use strict;
use warnings;
use Crypt::Digest::SHA256 'sha256_b64u';
open my $fh_in, '<', $ARGV[0] or die $!;
open my $fh_out, '>', "$ARGV[0].new" or die $!;
while (my $line = <$fh_in>) {
# no need to chomp because we don't touch the last line
my @fields = split /,/, $line;
$fields[1] = sha256_b64u($fields[1]);
print $fh_out join ',', @fields;
}
按如下方式运行:
$ perl foo.pl example.csv
您的新文件将命名为example.csv.new
。
答案 1 :(得分:1)
另一种Python解决方案,专注于速度,但也关注可维护性。
#!/usr/bin/python3
import argparse
import hashlib
import re
parser = argparse.ArgumentParser(description='CSV swaper')
parser.add_argument(
'-f',
'--file',
dest='file_path',
type=str,
required=True,
help='The CSV file path.')
def hash_user(users, user):
try:
return users[user]
except KeyError:
id_ = int(hashlib.md5(user.encode('utf-8')).hexdigest(), 16)
users[user] = id_
return id_
def main():
args = parser.parse_args()
username_extractor = re.compile(r',([\s\S]*?),')
users = {}
counter = 0
templ = ',{},'
with open(args.file_path) as file:
with open('output.csv', 'w') as output:
line = file.readline()
while line:
try:
counter += 1
if counter == 1:
continue
username = username_extractor.search(line).groups()[0]
hashuser = hash_user(users, username)
output.write(username_extractor.sub(
templ.format(hashuser), line)
)
except StopIteration:
break
except:
print('Malformed line at {}'.format(counter))
finally:
line = file.readline()
if __name__ == '__main__':
main()
仍然有一些点可以优化,但中心点可以基于do try
而不是check,并且在重复用户不必重新删除用户名的情况下保存用户哈希值。 / p>
另外,您是否会在多核主机上运行它?..使用线程可以很容易地改进它。
答案 2 :(得分:0)
这个Python程序可能会做你想要的。您可以在命令行上传递要转换的文件名:
$ python this_program.py file1.csv file2.csv
import fileinput
import csv
import sys
import hashlib
class stdout:
def write(self, *args):
sys.stdout.write(*args)
input = fileinput.input(inplace=True, backup=".bak", mode='rb')
reader = csv.reader(input)
writer = csv.writer(stdout())
for row in reader:
row[1] = hashlib.sha256(row[1]).hexdigest()
writer.writerow(row)
答案 3 :(得分:0)
由于您在原始尝试中使用了awk
,因此awk
awk -F"," 'BEGIN{i=0;}
{if (unique_names[$2] == "") {
unique_names[$2]="Unique"i;
i++;
}
$2=unique_names[$2];
print $0}'