ฉันจะทำการแทนที่ Perl บนสตริงในขณะที่เก็บต้นฉบับได้อย่างไร


180

ใน Perl เป็นวิธีที่ดีในการดำเนินการแทนบนสตริงโดยใช้การแสดงออกปกติและเก็บค่าไว้ในตัวแปรที่แตกต่างกันโดยไม่ต้องเปลี่ยนต้นฉบับได้อย่างไร

ฉันมักจะเพียงแค่คัดลอกสตริงไปยังตัวแปรใหม่แล้วผูกไว้กับs///regex ที่จะแทนที่ในสตริงใหม่ แต่ฉันสงสัยว่ามีวิธีที่ดีกว่าการทำเช่นนี้?

$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
ไม่ว่าจะภายใต้การใช้งานอย่างเข้มงวดหรือไม่ก็ตาม การกำหนดขอบเขตตัวแปรให้น้อยที่สุด ++
ysth

ฉันสงสัยว่าจะมีบางสิ่งที่เหมือนกันmy $new = $_ for $old =~ s/foo/bar;ไหม
เบอนัวต์

2
@Benoit ฉันเชื่อว่าคุณหมายถึง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
คุณลืมgregex อันดับต้น ๆ ของคุณหรือไม่
mareoraft


10

วิธีแก้ปัญหาแบบใช้ครั้งเดียวมีประโยชน์มากกว่า shibboleth มากกว่ารหัสที่ดี ผู้เขียนโค้ด Perl ที่ดีจะรู้และเข้าใจ แต่มันมีความโปร่งใสน้อยกว่าและอ่านง่ายกว่าคูเปอร์เลเยอร์การคัดลอกและแก้ไขสองบรรทัดที่คุณเริ่มต้น

กล่าวอีกนัยหนึ่งวิธีที่ดีในการทำเช่นนี้คือวิธีที่คุณทำไปแล้ว ข้อสรุปที่ไม่จำเป็นที่ค่าใช้จ่ายในการอ่านไม่ได้ชนะ


อ้า แต่รุ่นหนึ่งบรรทัดไม่อยู่ภายใต้ข้อผิดพลาดในคำถามของการแก้ไขสตริงที่ไม่ตั้งใจโดยไม่ตั้งใจ
ysth

รุ่นหนึ่งบรรทัด <i> หากดำเนินการอย่างถูกต้อง </i> ไม่ใช่หัวข้อจริง แต่นั่นเป็นปัญหาแยกต่างหาก
Josh Millard

9
คุณอาจคิดว่าเป็นการกระชับที่ไม่จำเป็น แต่การพิมพ์ชื่อตัวแปรสองครั้งเพื่อใช้ครั้งเดียวคือสองเท่าของจำนวนจุดที่ล้มเหลว สามารถอ่านได้อย่างสมบูรณ์แบบสำหรับผู้ที่รู้ภาษาและแม้กระทั่งในหลักสูตร <i> การเรียนรู้ Perl </i> ของเรา
brian d foy

1

อีกวิธีการแก้ปัญหาก่อน 5.14: http://www.perlmonks.org/?node_id=346719 (ดูโพสต์ของ japhy)

ขณะที่วิธีการของเขาใช้mapมันยังทำงานได้ดีสำหรับอาร์เรย์ แต่ต้องการ cascading mapเพื่อสร้างอาร์เรย์ชั่วคราว (มิฉะนั้นจะถูกปรับเปลี่ยนต้นฉบับ):

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

1

ฉันเกลียดฟู่และบาร์ .. ใครที่ฝันถึงคำศัพท์ที่ไม่สื่อความหมายเหล่านี้ในการเขียนโปรแกรมล่ะ?

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
Pascal

2
ดู ... ถ้า JoGotta ใช้แบบดั้งเดิมและคุ้นเคยfooและbarคำตอบของเขาจะแม่นยำ พิสูจน์อีกครั้งว่าศุลกากรมีอยู่สำหรับเหตุผลและบทเรียนที่ได้เรียนรู้เพียงวิธีที่ยาก ;)
Jon

-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จะได้รับการควบคุมที่ดีกว่า: ตัวอย่างเช่นหากคุณต้องการปิดคำเตือนชั่วคราวในบล็อกรหัส
เกล็นแจ็
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.