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

У меня есть список фраз в одном файле (" phrases "), каждое существо на своей линии.

У меня также есть другой файл, который содержит список слов, каждое в строке (" words ").

Я хочу добавить звездочку в конце каждой фразы в " phrases ", который начинается со слова, указанного в" words ".

Например:

Файл " phrases ":

gone are the days
hello kitty
five and a half
these apples are green

Файл " words ":

five
gone

Ожидаемый результат в " phrases "после операции:

gone are the days *
hello kitty
five and a half *
these apples are green

Что я сделал до сих пор, так это:

parallel -j0 -a words -q perl -i -ne 'print "$1 *" if /^({}\s.*)$/' phrases

Но это усекает файл и иногда (не всегда) выдает мне эту ошибку:

Не удается удалить фразы: нет такого файла или каталога, пропустите файл.

Поскольку изменения будут вноситься одновременно, я намерен найти и заменить ТОЛЬКО те строки, которые начинаются со слова, оставляя другие без изменений. В противном случае parallel параллельное выполнение перезапишет друг друга.

Я открыт для других одновременных методов.

3 ответа

Решение

Это не подходит для параллельной обработки, потому что самая дорогая операция, которую вы можете сделать - обычно - чтение с диска. Процессор намного быстрее.

Ваша проблема не сильно загружает процессор, поэтому вы не получите большого преимущества от параллельной работы. И что еще хуже - как вы обнаружили - вы вызываете состояние гонки, которое может привести к засорению файлов.

Практически говоря, дисковый ввод-вывод выполняется частями - несколько K - с диска, который извлекается в кэш и затем подается в ОС таким образом, что вы можете притвориться, что read работает побайтово

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

Попытка распараллелить и перемежить этот процесс в лучшем случае не имеет никакого эффекта и может ухудшить ситуацию.

Так что, имея это в виду, вам лучше не пытаться проводить параллели, а вместо этого:

#!/usr/bin/env perl

use strict;
use warnings;

open ( my $words_fh, '<', 'words' ) or die $!; 
my $words = join '|', map { s/\n//r } <$words_fh>;
   $words = qr/\b(?:$words)\b/;
close ( $words_fh );

print "Using match regex of: ", $words, "\n";

open ( my $phrases_fh, '<', 'phrases' ) or die $!;
while ( <$phrases_fh> ) { 
  if (m/$words/) {
      s/$/ */;
  }
  print;
} 

Перенаправить вывод в нужное место.

Самый дорогой бит - чтение файлов - он делает это только один раз. Повторный вызов механизма регулярных выражений для одной и той же строки для каждого поискового запроса также будет дорогостоящим, потому что вы будете делать это N * M раз, где N - количество слов, а M - количество строк.

Поэтому вместо этого мы скомпилируем одно регулярное выражение и сопоставим его, используя нулевую ширину \b маркер границы слова (чтобы он не совпадал с подстрокой).

Примечание - мы не цитируем содержимое words - это может быть ошибка или особенность, потому что это означает, что вы можете добавить регулярное выражение в микс. (И это может сломаться, когда мы скомпилируем наше регулярное выражение).

Если вы хотите убедиться, что это "буквально", то:

my $words = join '"', map { quotemeta } map { s/\n//r } <$words_fh>; 

Почему эта проблема не параллельное планирование процессов?

Просто представьте себе внутреннюю цепочку зависимостей значений, которые необходимы для вывода в заданный, строгий [SEQ] -контролируемый путь в самом конце процесса вывода.

Факт № 1)
хотя очень легко выделить более одного процесса, используя синтаксис gnu -rallel, чтобы сделать его обязательным для выполнения на уровне оболочки, это вовсе не означает, что каждый случай таких сосуществующих процессов допускает гладкое и умное "просто" по совпадению [CONCURRENT] или даже правда- [PARALLEL] планирование процесса бесплатно.

Факт № 2)
file:phrases должны быть обработаны в чистом [SERIAL] образом, как естественный порядок (SEQ) имеет значение и должна быть сохранена даже для результирующего файлового вывода.

Факт № 3)
каждый файл на основе [SERIAL] процесс, ни "просто"- [CONCURRENT] ни правда- [PARALLEL] До тех пор, пока не изобретен способ, как сделать так, чтобы головки устройства чтения жесткого диска в один момент времени находились в нескольких местах (что значительно превосходит даже квантовую запутанность, трюки суперпозиции и магию в субатомном масштабе).

Факт № 4)
Конечно, можно представить себе какое-то пространство для параллельной обработки, как только [SEQ] -читание от file:phrases известно, где может произойти некоторое ускорение, если более одного ([SEQ] поиск) будет обработан - но, опять же, на основе условия, что есть оба ресурса (для одновременного выполнения нескольких поисков, без какого-либо неблагоприятного влияния на поток процессов в случае, если не все параллельные процессы получают выполняется без проблем), и все они должны иметь "предварительно кэшированное" все "известное" статическое содержимое file:words (иначе это не поможет), чтобы как-то сбежать от следующего ([SEQ] опять) чисто- [SERIAL]fileIO - [SEQ] упорядоченная повторная обработка с ограничением одновременной пропускной способности при поиске соответствия по первому слову, в настоящее время настоятельно необходимая форма синтаксиса gnu-параллелизма для более чем одного words -ползание процессов.


Можно легко заплатить больше, чем можно было бы получить от:

Неправильное или даже наивное планирование процессов может и действительно приводит к дополнительным расходам, которых никогда не было в [SERIAL] выполнение кода. Даже самые легкие дополнительные издержки платформ параллелизма (и эти затраты масштабируются с N, если многие исполнения параллельного кода оказываются крайне материализованными, буквально любой ценой)

Пожалуйста, внимательно прочитайте подробную информацию о Законе Амдала, лучше всего его современную критику, в том числе современную переформулировку, включающую как дополнительные надбавки к издержкам, так и неделимость кода при выполнении кода, не зависящую от числа процессоры в наличии. Несмотря на свою первоначальную формулировку 50 лет назад, современные массивно-параллельные экосистемы исполнения кода все еще не могут лучше учиться из зависимостей этого основного закона, от которых никто никогда не сможет избежать.

Поэтому всегда проверяйте все [SEQ] -зависимости в цепочке зависимостей проблемы.
Поэтому всегда проверяйте все [PAR] накладные расходы, прежде чем даже мечтать о производительности.

perl -i -pe'
    BEGIN {
       my $words_qfn = shift(@ARGV);
       open(my $words_fh, "<", $words_qfn) or die $!;
       chomp( my @words = <$words_fh> );
       my $alt = join "|", map quotemeta, @words;
       $re = qr/^(?:$alt)\b.*\K/;
    }
    s/$re/ */;
' words phrases
Другие вопросы по тегам