Intereting Posts
Prepackage Arch Linux (ARM) с пакетами перед установкой Использовать read как подсказку внутри цикла while, управляемого read? Есть ли опция / команда для дифференциации файлов на основе состояния копии файла в каталоге? удалить добавленный путь из PATH? Драйвер ATI и проблема с загрузкой «Запуск тимидности alsa midi emulation» Как узнать, какой ящик дерева устройств (dtb-файл) я использую? Когда следует перезагружать компьютер после обновления? Есть ли инструмент CLI, который будет префикс строки JSON Что такое верхняя левая кнопка в Windows KDE? подавление / dev / watchdog системное сообщение Доступ к последней выполненной команде и ее изменение перед выполнением в VIM `uniq` не в режиме реального времени, когда В цикле над массивом добавьте элемент в массив Каждые несколько минут меняется ориентация экрана Как упаковать отдельно расположенные файлы в одну структуру папок?

Удалить несколько строк из файла в командной строке, высокая производительность

Существует ли элегантный, высокопроизводительный однострочный способ удаления нескольких полных строк из входных данных?

Я обрабатываю большие текстовые файлы, например, 1 миллион строк во входном файле и 100 000 совпадающих строк в хит-файле . У меня есть скрипт на Perl, который загружает хит-файл в хеш, а затем проверяет все «слова» в каждой строке входного файла , но для моего рабочего процесса я предпочел бы простую команду своему сценарию.

Функциональность, которую я ищу, эквивалентна этой:

perl -pe 's/\b(string1|string2|string3)\b)//g' 

или этот метод вложенного sed:

 sed -e "$(sed 's:.*:s/&//ig:' hitfile)" inputfile 

или зацикливание в оболочке:

 while read w; do sed -i "s/$w//ig" hitfile ; done < inputfile 

Но это слишком дорого. Этот немного более эффективный метод работает ( Как удалить все вхождения списка слов из текстового файла? ), Но он все еще очень медленный:

 perl -Mopen=locale -Mutf8 -lpe ' BEGIN{open(A,"hitfile"); chomp(@k = )} for $w (@k){s/(^|[ ,.—_;-])\Q$w\E([ ,.—_;-]|$)/$1$2/ig}' inputfile 

Но есть ли другие хитрости, чтобы сделать это более кратко? Какие-то другие команды или метод Unix я пропускаю? Мне не нужно регулярное выражение, мне нужно только сравнить чистые / точные строки с хешем (для скорости). то есть “сосна” не должна соответствовать “ананасу”, но она должна соответствовать “(сосне)”.

Например, у меня была идея расширить слова в файле на отдельные строки

До:

 Hello, world! 

После:

 ¶ Hello , world ! 

А затем обработайте с помощью grep -vf, а затем пересоберите / соедините строки.

Любые другие идеи, которые будут работать быстро и легко?

Насколько велик ваш hitfile ? Не могли бы вы показать некоторые реальные примеры того, что вы пытаетесь сделать? Поскольку вы не предоставили более подробную информацию о своих входных данных, это всего лишь одна из идей, чтобы попробовать и сравнить с вашими реальными данными .

Регулярные выражения Perl могут стать довольно большими, и одно регулярное выражение позволит вам изменить входной файл за один проход. Здесь я использую /usr/share/dict/words в качестве примера для построения огромного регулярного выражения, у меня ~ 99 тыс. Строк и размер ~ 1 МБ.

 use warnings; use strict; use open qw/:std :encoding(UTF-8)/; my ($big_regex) = do { open my $wfh, '<', '/usr/share/dict/words' or die $!; chomp( my @words = <$wfh> ); map { qr/\b(?:$_)\b/ } join '|', map {quotemeta} sort { length $b <=> length $a or $a cmp $b } @words }; while (<>) { s/$big_regex//g; print; } 

Мне не нужно регулярное выражение, мне нужно только сравнить чистые / точные строки с хешем (для скорости). то есть “сосна” не должна соответствовать “ананасу”, но она должна соответствовать “(сосне)”.

Если «pine» не должно совпадать с «pineapple», необходимо проверить символы до и после появления «pine» на входе. Хотя, конечно, это возможно при использовании фиксированных строковых методов, похоже, что вы ищете концепцию регулярных выражений границ слов ( \b ).

Существует ли элегантный, высокопроизводительный однострочный способ … для моего рабочего процесса я бы предпочел простую команду своему сценарию.

Я не уверен, что согласен с этим мнением. Что не так с perl script.pl ? Вы можете использовать его с перенаправлениями оболочки / трубами, как однострочник. Помещение кода в сценарий освободит вашу командную строку и позволит вам делать сложные вещи, не пытаясь объединить все это в одну строку. Плюс, короткая не обязательно означает быструю.

Другая причина, по которой вы можете захотеть использовать скрипт, – это наличие нескольких входных файлов. С помощью кода, который я показал выше, построение регулярного выражения довольно дорого, поэтому многократный вызов сценария будет дорогостоящим – обработка нескольких файлов в одном сценарии устранит эти издержки. Мне нравится принцип UNIX, но для больших данных вызов нескольких процессов (иногда многократно) и передача данных между ними не всегда самый эффективный метод, и может помочь рационализация всего этого в одной программе.


Обновление : Согласно комментариям, достаточно веревки, чтобы выстрелить себе в ногу. Код, который делает то же самое, что и выше, в одной строке:

 perl -CDS -ple 'BEGIN{local$/;($r)=map{qr/\b(?:$_)\b/}join"|",map{quotemeta}sort{length$b<=>length$a}split/\n/,<>}s/$r//g' /usr/share/dict/words input.txt