Làm cách nào để thực hiện thay thế Perl trên chuỗi trong khi vẫn giữ nguyên bản gốc?


180

Trong Perl, cách tốt nhất để thực hiện thay thế trên một chuỗi bằng cách sử dụng biểu thức chính quy và lưu trữ giá trị trong một biến khác, mà không thay đổi bản gốc là gì?

Tôi thường chỉ sao chép chuỗi vào một biến mới sau đó liên kết nó với s///regex thực hiện thay thế trên chuỗi mới, nhưng tôi đã tự hỏi liệu có cách nào tốt hơn để làm điều này không?

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

Câu trả lời:


257

Đây là thành ngữ tôi luôn sử dụng để lấy một bản sao đã sửa đổi của chuỗi mà không thay đổi bản gốc:

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

Trong perl 5.14.0 trở lên, bạn có thể sử dụng công cụ /r sửa đổi thay thế không phá hủy mới :

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

Lưu ý: Các giải pháp trên hoạt động mà không gquá. Họ cũng làm việc với bất kỳ sửa đổi khác.


6
Có hay không sử dụng nghiêm ngặt. Phạm vi tối thiểu của các biến ++
ysth

Tôi đã tự hỏi nếu một cái gì đó như my $new = $_ for $old =~ s/foo/bar;sẽ làm việc?
Benoit

2
@Benoit, tôi tin rằng bạn có nghĩa là s/foo/bar/ for my $newstring = $oldstring;nó hoạt động, nhưng nó xa lạ hơn.
ikegami

43

Tuyên bố:

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

Tương đương với:

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

Ngoài ra, kể từ Perl 5.13.2, bạn có thể sử dụng /rđể thực hiện thay thế không phá hủy:

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

3
Bạn đã quên gtrong regex hàng đầu của bạn?
mareoraft

23

Dưới use strict, nói:

(my $new = $original) =~ s/foo/bar/;

thay thế.


10

Giải pháp một lớp lót hữu ích như một shibboleth hơn là mã tốt; Các lập trình viên Perl giỏi sẽ biết và hiểu nó, nhưng nó ít minh bạch và dễ đọc hơn so với bộ ghép hai dòng và sao chép hai dòng mà bạn bắt đầu.

Nói cách khác, một cách tốt để làm điều này là cách bạn đã làm nó. Sự can thiệp không cần thiết với chi phí dễ đọc không phải là một chiến thắng.


À, nhưng phiên bản một dòng không bị lỗi trong câu hỏi vô tình sửa đổi chuỗi sai.
ysth

Phiên bản một dòng, <i> nếu được thực thi chính xác </ i>, không phải là chủ đề, đúng. Nhưng đó là một vấn đề riêng biệt.
Josh Millard

9
Bạn có thể nghĩ rằng đó là sự can thiệp không cần thiết, nhưng phải gõ một tên biến hai lần để sử dụng nó một lần thì gấp đôi số điểm thất bại. Nó hoàn toàn dễ đọc đối với những người biết ngôn ngữ và thậm chí nó còn nằm trong khóa học <i> Learning Perl </ i> của chúng tôi.
brian d foy

1

Một giải pháp trước 5.14 khác: http://www.perlmonks.org/?node_id=346719 (xem bài đăng của japhy)

Theo cách tiếp cận của anh ta sử dụng map, nó cũng hoạt động tốt cho các mảng, nhưng yêu cầu xếp tầng mapđể tạo ra một mảng tạm thời (nếu không thì bản gốc sẽ được sửa đổi):

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

1

Tôi ghét foo và bar .. ai đã mơ những thuật ngữ không mô tả này trong lập trình?

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
Điều này khác với bản gốc như thế nào? (Và tôi nghĩ rằng bạn muốn =~ s.)
Teepeemm

Sai lầm Clbuttic. Đầu ra thực tế của mã đó lànewword donotnewword newword donotnewword newword donotnewword
Pascal

2
Xem ... nếu JoGotta đã sử dụng truyền thống và quen thuộc foobar, câu trả lời của anh ta sẽ chính xác. Chứng minh, một lần nữa, phong tục tồn tại vì một lý do và bài học chỉ được học một cách khó khăn. ;)
Jon

-1

Nếu bạn viết Perl với use strict;, thì bạn sẽ thấy rằng cú pháp một dòng không hợp lệ, ngay cả khi được khai báo.

Với:

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

Bạn lấy:

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

Thay vào đó, cú pháp mà bạn đã sử dụng, trong khi một dòng dài hơn, là cách chính xác về mặt cú pháp để thực hiện use strict;. Đối với tôi, sử dụng use strict;bây giờ chỉ là một thói quen. Tôi làm nó tự động. Mọi người nên.

#!/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
Nếu bạn use warnings;thay vì -w, bạn có được quyền kiểm soát lớn hơn: ví dụ: nếu bạn muốn tạm thời tắt cảnh báo trong một khối mã.
glenn jackman
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.