Як виконати заміну Perl на рядку, зберігаючи оригінал?


180

У Perl, що є хорошим способом виконати заміну на рядку, використовуючи регулярний вираз і зберегти значення в іншій змінній, не змінюючи оригінал?

Зазвичай я просто копіюю рядок до нової змінної, а потім прив'язую її до s///регулярного виразу, який робить заміну на нову рядок, але мені було цікаво, чи є кращий спосіб це зробити?

$newstring = $oldstring;
$newstring =~ s/foo/bar/g;

Відповіді:


257

Це ідіома, яку я завжди використовував для отримання модифікованої копії рядка без зміни оригіналу:

(my $newstring = $oldstring) =~ s/foo/bar/g;

У perl 5.14.0 або пізнішої версії ви можете використовувати новий /r неруйнівний модифікатор заміни :

my $newstring = $oldstring =~ s/foo/bar/gr; 

Примітка. Вищезазначені рішення працюють і без того g. Вони також працюють з будь-якими іншими модифікаторами.


6
Незалежно від використання чи ні. Мінімальний
діапазон

Мені було цікаво, чи my $new = $_ for $old =~ s/foo/bar;спрацює щось подібне ?
Бенуа

2
@ Бенуа, я вважаю, ти маєш на увазі, що s/foo/bar/ for my $newstring = $oldstring;це працює, але це набагато дивніше.
ikegami

43

Заява:

(my $newstring = $oldstring) =~ s/foo/bar/g;

Що еквівалентно:

my $newstring = $oldstring;
$newstring =~ s/foo/bar/g;

Як варіант Perl 5.13.2 ви можете використовувати /rзаміну без руйнування:

use 5.013;
#...
my $newstring = $oldstring =~ s/foo/bar/gr;

3
Ви забули про gсвій головний регекс?
мареофт


10

Однолінійне рішення корисніше як шибболет, ніж хороший код; хороші кодери Perl знають це і розуміють це, але він набагато менш прозорий і читабельний, ніж дворядковий пакет копіювання та модифікації, з якого ви починаєте.

Іншими словами, хороший спосіб зробити це так, як ви це вже робите. Непотрібна чіткість за рахунок читабельності - це не виграш.


Так, але версія одного рядка не підлягає помилці у питанні ненавмисної зміни неправильної рядки.
ysth

Версія в одному рядку, <i> якщо правильно виконана </i>, не є предметом, правда. Але це окреме питання.
Джош Міллард

9
Ви можете подумати, що це непотрібність чіткості, але потрібно вводити ім’я змінної двічі, щоб використовувати її один раз, удвічі перевищує кількість балів. Це чудово читається людям, які знають мову, і це навіть у нашому курсі <i> Perl Learning </i>.
Брайан d foy

1

Ще одне рішення до 5.14: http://www.perlmonks.org/?node_id=346719 (див. Повідомлення Джафі)

Оскільки використовується його підхід map, він також добре працює для масивів, але вимагає каскадування mapдля створення тимчасового масиву (інакше оригінал буде змінено):

my @orig = ('this', 'this sucks', 'what is this?');
my @list = map { s/this/that/; $_ } map { $_ } @orig;
# @orig unmodified

1

Я ненавиджу foo and bar .. хто все-таки придумав ці не описові терміни в програмуванні?

my $oldstring = "replace donotreplace replace donotreplace replace donotreplace";

my $newstring = $oldstring;
$newstring =~ s/replace/newword/g; # inplace replacement

print $newstring;
%: newword donotreplace newword donotreplace newword donotreplace

2
Чим це відрізняється від оригіналу? (І я думаю, що ти хочеш =~ s.)
Teepeemm

Помилка Clbuttic. Фактичний вихід цього кодуnewword donotnewword newword donotnewword newword donotnewword
Паскаль

2
Дивіться ... якби ДжоГотта використав традиційне і звичне, fooі barйого відповідь була б точною. Доводячись, митні звичаї існують не просто так, а уроки засвоюються лише важким шляхом. ;)
Джон

-1

Якщо ви пишете Perl з use strict;, ви побачите, що синтаксис одного рядка недійсний, навіть якщо він оголошений.

З:

my ($newstring = $oldstring) =~ s/foo/bar/;

Ви отримуєте:

Can't declare scalar assignment in "my" at script.pl line 7, near ") =~"
Execution of script.pl aborted due to compilation errors.

Натомість синтаксис, який ви використовували, а рядок довший - це синтаксично правильний спосіб зробити це use strict;. Для мене use strict;зараз використання звички. Я роблю це автоматично. Кожен повинен.

#!/usr/bin/env perl -wT

use strict;

my $oldstring = "foo one foo two foo three";
my $newstring = $oldstring;
$newstring =~ s/foo/bar/g;

print "$oldstring","\n";
print "$newstring","\n";

1
Якщо ви use warnings;замість цього -w, ви отримуєте більш високий контроль: наприклад, якщо ви хочете тимчасово вимкнути попередження в блоці коду.
glenn jackman
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.