Использование bash
и csvformat
из набораcsvkit
для изменения разделителя полей с запятой на новую строку:
$ csvformat -D $'\n' file
field1
field2
field3
field4
Предполагается, что ввод в file
представляет собой правильно отформатированный CSV. Это также правильно обработает встроенные запятые:
$ cat file
"field,1",field2,field3,field4
$ csvformat -D $'\n' file
field,1
field2
field3
field4
$ cat tst.awk
BEGIN {
dots = sprintf("%*s",1000,"")
gsub(/ /,".",dots)
resSingle = "res-single"
resLength = "res-length"
}
{ lc = tolower($0) }
NR==FNR {
lgth = length($0)
str2lgth[lc] = lgth
str2dots[lc] = substr(dots,1,lgth)
next
}
{
for (str in str2lgth) {
if ( s=index(lc,str) ) {
bef = substr($0,1,s-1)
aft = substr($0,s+str2lgth[str])
print bef "." aft > resSingle
print bef str2dots[str] aft > resLength
}
}
}
.
$ awk -f tst.awk fileA fileB
$ cat res-single
12.1991
ari.#!
.agnes#!
.45
$ cat res-length
12....1991
ari.....#!
...agnes#!
...45
Вышеприведенное предполагает, что ни одна строка в файле A не будет длиннее 1000 символов, если это не так, выберите большее число или мы можем добавить код для его вычисления, если это необходимо. Это также предполагает, что вам все равно, в каком порядке строки из файла A ищутся в файле B, и что вы хотите выполнить сравнение строк, а не регулярное выражение, оба снова тривиальные настройки, если это не то, что вы хотите.
РЕДАКТИРОВАТЬ в ответ на ваш комментарий ниже, вот как изменить приведенное выше, если вы не можете статически определить максимальную длину для строк из файла A (, даже не 100 000 символов? )и так нужно выяснить макс, а строки из файла А все в нижнем регистре:
NR==FNR {
lgth = length($0)
str2lgth[$0] = lgth
maxLgth = (lgth > maxLgth ? lgth : maxLgth)
next
}
FNR==1 {
dots = sprintf("%*s",maxLgth,"")
gsub(/ /,".",dots)
for ( str in str2lgth ) {
str2dots[str] = substr(dots,1,str2lgth[str])
}
resSingle = "res-single"
resLength = "res-length"
}
{
lc = tolower($0)
for (str in str2lgth) {
if ( s=index(lc,str) ) {
bef = substr($0,1,s-1)
aft = substr($0,s+str2lgth[str])
print bef "." aft > resSingle
print bef str2dots[str] aft > resLength
}
}
}
Здесь вы можете использовать простой подход, основанный на Perl.
Метод:
заполнить хэш %h, ключами которого являются строчные строки (без новых строк )файла A, а значениями являются эквивалентное количество точек.
Затем для каждой строки файла B мы проверяем наличие какого-либо ключа хеша %h без учета регистра. Если да, то мы печатаем данные прематча, совпадения и постматча в файлы res -single и res -length. Если вам нужен только первый матч, раскомментируйте «последний» оператор.
$ perl -Mautodie -lne '
BEGIN {
open *{"FH$_"}, ">", qw[res-single res-length][$_] for 0..1;
do{
local @ARGV = pop;
$h{do{chomp;lc;}} = s/././gr =~ tr/\n//dr while <>;
@h = keys %h;
};
}
for my $h ( @h ) {
if ( /\Q$h/pi ) {
my($p, $q) = (${^PREMATCH}, ${^POSTMATCH});
print {*{"FH$_"}} $p, (".", $h{$h})[$_], $q for 0..1;
#last;
}
}
' fileB fileA
$ more res-*
::::::::::::::
res-length
::::::::::::::
12....1991
ari.....#!
...agnes#!
...45
::::::::::::::
res-single
::::::::::::::
12.1991
ari.#!
.agnes#!
.45
Оптимизированное решение Chttps://github.com/dizcza/people-names-as-passwords/blob/master/src/create_masks.c
Я использовал структуру данных trie, которая позволила мне разобрать 2 миллиарда строк fileB
с 43 тысячами строк fileA
всего за 12 минут!
Спасибо всем за участие.