Может ли perl заменить несколько ключевых слов собственным словом-заменителем за один раз? - PullRequest
8 голосов
/ 20 января 2012

Рассмотрим текстовый файл с содержанием:

apple apple pear plum apple cherry pear apple  
cherry plum plum pear apple cherry pear pear apple plum

И рассмотрим однострочник perl:

perl -pe "s/apple/green/g and s/pear/yellow/g and s/plum/blue/g and s/cherry/red/g" < fruits.txt

Это заменяет каждый фрукт своим цветом.
Теперь, можно ли это как-то сделать за один раз /// вместо четырех?

Меня также беспокоит порядок слов фруктов.
Если мой образец не включает «яблоко», ни одна из других замен не будет завершена. Как мне это исправить?

Обратите внимание: я хочу сохранить решение как однострочное.
Поэтому определение хешей, чтение в файлах и другие решения, требующие много строк кода на Perl, не продвигают меня вперед.

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

Ответы [ 5 ]

12 голосов
/ 20 января 2012

Заменить

perl -pe's/apple/green/g and s/pear/yellow/g and ...' fruits.txt

с

perl -pe's/apple/green/g; s/pear/yellow/g; ...' fruits.txt

Быстрее и не имеет проблем с a => b b => c:

perl -pe'
   BEGIN {
      %subs=qw(apple green pear yellow plum blue cherry red);
      $re=join "|", map quotemeta, keys %subs;
      $re = qr/($re)/;
   }
   s/$re/$subs{$1}/g;
' fruits.txt

Другие потенциальные проблемы:

  • Что делать, если вы хотите заменить apple, но не apples?
  • Что если хеш имеет ключи bee и beer?

Обе проблемы могут быть решены с помощью подходящего крепления (например, $re = qr/\b($re)\b/). Второе также может быть решено путем сортировки ключей путем уменьшения длины (sort { length($b) <=> length($a) } keys %subs).

(Вы можете удалить разрывы строк, которые я добавил для удобства чтения.)

5 голосов
/ 20 января 2012

perl -pe '%a=qw(apple green pear yellow plum blue cherry red);$b=join("|",keys %a);s/($b)/$a{$1}/g' < fruits.txt

4 голосов
/ 20 января 2012
perl -E 'my %h = qw(apple green foo bar); say "apple foo" =~ s/(apple|foo)/$h{$1}/rge;'
1 голос
/ 20 января 2012

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

 $ perl5.14.2 -nE 'print s/(\S+)/$h{$1}?$h{$1}:$1/rge}BEGIN{%h=qw(apple green pear yellow plum blue cherry red)'

Если проблема несколько сложнее, моя однострочная строка будет выглядеть так:

 $ perl fruits2color

Некоторые из других ответов объединяют регулярные выражения. В не однострочной программе я, вероятно, сделал бы это с помощью чего-то вроде Regex :: Assemble или Regexp :: Trie . Эти модули могут создавать эффективные чередования.

0 голосов
/ 20 января 2012

Кто сказал, что хэши не могут запомнить их порядок :)?

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

Используйте Tie::IxHash от CPAN.

use Tie::IxHash;
tie my %myhash, 'Tie::IxHash';

for (my $i=0; $i<20; $i++) {
    $myhash{$i} = 2*$i;
}

my @keys = keys %myhash;
# @keys = (0,1,2,3,...)

$ perl -MTie::IxHash -pe '
         BEGIN { tie %h, "Tie::IxHash";
                 %h = qw< apple green pear yellow >;
               }
         s<($_)>/$h{$1}/g for keys %h;
        ' file
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...