คุณมีเคล็ดลับทั่วไปอะไรสำหรับการเล่นกอล์ฟใน Perl ฉันกำลังมองหาความคิดที่สามารถนำไปใช้กับปัญหารหัสกอล์ฟโดยทั่วไปซึ่งอย่างน้อยค่อนข้างเฉพาะกับ Perl (เช่น "ลบความคิดเห็น" ไม่ใช่คำตอบ) กรุณาโพสต์หนึ่งเคล็ดลับต่อคำตอบ
คุณมีเคล็ดลับทั่วไปอะไรสำหรับการเล่นกอล์ฟใน Perl ฉันกำลังมองหาความคิดที่สามารถนำไปใช้กับปัญหารหัสกอล์ฟโดยทั่วไปซึ่งอย่างน้อยค่อนข้างเฉพาะกับ Perl (เช่น "ลบความคิดเห็น" ไม่ใช่คำตอบ) กรุณาโพสต์หนึ่งเคล็ดลับต่อคำตอบ
คำตอบ:
นั่นคือเคล็ดลับที่สำคัญที่สุดในการเล่นกอล์ฟ Perl ที่คุณต้องรู้ เมื่อใดก็ตามที่คุณดูลำดับตัวละครที่ยาวเกินไปที่คุณต้องทำเพื่อให้งานสำเร็จลุล่วงถามตัวเองว่าไม่มีวิธีอื่นที่จะได้รับผลกระทบเดียวกันโดยใช้คุณสมบัติที่แตกต่างกันหรือไม่ มักจะมี นี่เป็นเพียงไม่กี่:
~~
บังคับใช้บริบทเกลาและเป็น 4 scalar
ตัวอักษรที่สั้นกว่า
y///c
หนึ่งตัวอักษรสั้นกว่าlength
เมื่อรับความยาว$_
เป็น
ต้องการวนซ้ำตัวอักษรใน$_
หรือไม่ แทนที่ด้วยsplit//
/./gs
(หรือใช้/./g
ถ้าคุณยังต้องการที่จะข้ามบรรทัดใหม่.) งานนี้มีตัวแปรอื่น ๆ : เปลี่ยนด้วยsplit//,$x
$x=~/./gs
Perlin ทุกตัวจะส่งคืนสิ่งที่ print
ส่งคืน 1 เช่นเพื่อระบุ I / O ที่สำเร็จ หากคุณต้องการเริ่มต้น$_
เป็นค่าจริงเช่น$_=print$foo
อนุญาตให้คุณฆ่านกสองตัวด้วยหินก้อนเดียว
เกือบทุกคำสั่งใน Perl สามารถเขียนเป็นนิพจน์ทำให้สามารถใช้ในบริบทที่หลากหลายได้กว้างขึ้น หลายคำสั่งสามารถเป็นหลายนิพจน์ที่ถูกโยงเข้าด้วยกันด้วยเครื่องหมายจุลภาค การทดสอบสามารถทำได้กับตัวดำเนินการลัดวงจร?:
&&
||
และกับand
และor
ซึ่งทำสิ่งเดียวกัน แต่มีความสำคัญต่ำกว่าตัวดำเนินการอื่นทั้งหมด (รวมถึงการกำหนด) ลูปสามารถทำได้ผ่านทางหรือmap
grep
แม้คำหลักเช่นnext
, last
และreturn
สามารถนำมาใช้ในบริบทการแสดงออกถึงแม้ว่าพวกเขาไม่กลับ! การคำนึงถึงการแปลงรูปแบบเหล่านี้อยู่ในใจจะช่วยให้คุณมีโอกาสแทนที่โค้ดบล็อกด้วยนิพจน์ที่สามารถยัดเข้าไปในบริบทที่หลากหลาย
$foo
แล้ว มิฉะนั้น$_=1
จะสั้นกว่า$_=print""
และมีผลเหมือนกันมาก
$x
? มิฉะนั้นคุณก็สามารถทำและ/./gs
/./g
ตัวแปรพิเศษในทางที่ผิดของ Perl!
ตามที่ระบุไว้ในคำตอบก่อนหน้า$/
และ$"
จะเริ่มต้นโดยเริ่มต้นถึง"\n"
และ" "
ตามลำดับ
$,
และ$\
ถูกตั้งค่าเป็นทั้งค่าundef
เริ่มต้นและสั้นกว่า 3 ตัวอักษร
การตั้งค่า$\
เป็นค่าจะทำให้ผนวกเข้ากับทุกprint
ค่า ตัวอย่างเช่น: perl -ple '$\="=".hex.$/'
เป็นตัวแปลงเลขฐานสิบหกถึงทศนิยมที่มีประโยชน์
หากคุณไม่ได้อ่านไฟล์จากบรรทัดคำสั่งคุณสามารถใช้-i
สวิตช์บรรทัดคำสั่งเป็นช่องทางพิเศษสำหรับการป้อนสตริง $^I
ค่าของมันจะถูกเก็บไว้ใน
$=
บังคับให้ทุกสิ่งที่กำหนดให้มันเป็นจำนวนเต็ม ลองใช้งานperl -ple '$_=$==$_'
และมอบ inupts ต่างๆ เช่นเดียวกัน$-
บังคับให้ค่าเป็นจำนวนเต็มที่ไม่ใช่ลบ (เช่นเครื่องหมายขีดนำจะถือเป็นอักขระที่ไม่ใช่ตัวเลข)
คุณสามารถใช้$.
เป็นแฟล็กบูลีนที่ถูกรีเซ็ตเป็นค่าจริง (ไม่ใช่ศูนย์) ในทุกการวนซ้ำของwhile(<>)
ลูป
-n
และวงเล็บปีกกาที่ไม่มีใครเทียบเป็นที่ทราบกันดีว่าสวิตช์บรรทัดคำสั่ง-n
สามารถใช้เพื่อเรียกใช้สคริปต์หนึ่งครั้งสำหรับทุกบรรทัด
perl --help
พูดว่า:
-n assume "while (<>) { ... }" loop around program
สิ่งที่ไม่ได้พูดอย่างชัดเจนก็คือ Perl ไม่เพียง แต่คิดว่าวนรอบโปรแกรม มันอย่างแท้จริงล้อมwhile (<>) { ... }
รอบ
วิธีนี้คำสั่งต่อไปนี้เทียบเท่ากัน:
perl -e 'while(<>){code}morecode'
perl -ne 'code;END{morecode}'
perl -ne 'code}{morecode'
-p
และวงเล็บปีกกาที่ไม่มีใครเทียบเช่นเดียวกันกับที่กล่าวมาข้างต้น-p
สวิตช์ล้อมwhile (<>) { ... ; print }
รอบโปรแกรม
โดยใช้วงเล็บปีกกาตรงกันperl -p 'code}{morecode'
เท่านั้นจะพิมพ์ครั้งหลังจากการดำเนินการสำหรับทุกบรรทัดของการป้อนข้อมูลตามcode
morecode
เนื่องจาก$_
ไม่ได้กำหนดไว้เมื่อmorecode;print
มีการดำเนินการตัวแยกบันทึกการส่งออก$\
สามารถใช้ในทางที่ผิดเพื่อพิมพ์เอาท์พุทที่เกิดขึ้นจริง
ตัวอย่างเช่น
perl -pe '$\+=$_}{'
อ่านหนึ่งหมายเลขต่อบรรทัดจาก STDIN และพิมพ์ผลรวมของพวกเขา
#!perl -n
ในบรรทัดแรกใช่มั้ย
}for(...){
ระหว่างเครื่องมือจัดฟันก็มีประโยชน์เช่นกันเช่นcodegolf.stackexchange.com/a/25632
ใช้$_
เพื่อกำจัดการอ้างอิงสเกลาร์ มันเป็นตัวแปรพิเศษที่ใช้เป็นค่าเริ่มต้นโดยฟังก์ชั่นส่วนใหญ่และเพียงแค่ออกจากพารามิเตอร์เป็นทางลัดในการอ้างอิงตัวแปรนี้
โดยการเปลี่ยน$n
ไป$_
คุณสามารถเปลี่ยน$n=<>;chop$n;print$n
ไป$_=<>;chop;print
ที่นี่print
ฟังก์ชั่นพิมพ์เนื้อหาของ$_
โดยค่าเริ่มต้นและchop
ยังใช้งาน$_
ได้
$_=<>;
ต้องไม่ได้<>;
อ่านบรรทัดลง$_
โดยอัตโนมัติ?
$_=<>;print
<>;print
อันแรกกลับมาหาฉันในสิ่งที่ฉันพิมพ์ในขณะที่อีกอันหนึ่งไม่กลับมา
print while(<>)
โอ้ขอบคุณปรากฎว่าเกิดขึ้นเฉพาะในกรณีเช่น ถ้าไม่แน่ใจว่ามันเป็นกรณีพิเศษหรือมีบางตรรกะเชื่อมโยงกันอยู่เบื้องหลังมันไม่<>
's ส่วนร่วมในการperlop
มิได้while
เป็นส่วนหนึ่งของperlsyn
ดูเหมือนจะพูดถึงพฤติกรรมนี้
while(<>)
เป็นกรณีพิเศษที่จัดทำเป็นเอกสารใน perlsyn, I / O Operators: 'ถ้าหากสัญลักษณ์อินพุตเป็นสิ่งเดียวที่อยู่ในเงื่อนไขของคำสั่ง "while" (แม้ว่าจะปลอมเป็น "for (;;)" วนรอบ) ค่าจะถูกกำหนดให้กับตัวแปรทั่วโลกโดยอัตโนมัติ $ _, ทำลายสิ่งที่เคยมีมาก่อนหน้านี้ "
ใช้ตัวแปรพิเศษของ Perl ที่คุณสามารถทำได้เช่น:
$"
แทน" "
$/
แทน"\n"
พวกเขาได้รับประโยชน์เพิ่มเติมจากการเป็นตัวระบุความยาวหนึ่งตัวที่รับประกันได้ด้วยความช่วยเหลือจาก lexer สิ่งนี้ทำให้สามารถติดกับคำหลักที่ตามมาดังเช่นในprint$.for@_
รายการตัวแปรพิเศษทั้งหมดมีอยู่ที่นี่: ตัวแปรพิเศษ
qw
อย่าใช้ นี่เป็นการเสียอักขระสองตัวที่สามารถนำไปใช้ในทางที่ดีขึ้น ตัวอย่างเช่นอย่าเขียนสิ่งต่อไปนี้
@i=qw(unique value);
ใช้ barewords แทน
@i=(unique,value);
หรือถ้าคุณไม่สามารถใช้ barewords ให้ใช้glob
ไวยากรณ์
@i=<unique value>;
glob
ไวยากรณ์สามารถใช้สำหรับเอฟเฟ็กต์ที่น่าสนใจ
@i=<item{1,2,3}>;
ใช้โมเดอเรเตอร์ของคำสั่งแทนคำสั่งผสม
ข้อความสั่งแบบผสมมีแนวโน้มที่จะต้องใช้วงเล็บสำหรับอาร์กิวเมนต์และวงเล็บปีกกาสำหรับบล็อกในขณะที่ตัวดัดแปลงข้อความไม่ต้องการ
เปรียบเทียบ:
$a++,$b++while$n--
VS while($n--){$a++;$b++}
chop$,if$c
VS if($c){chop$,}
โปรดทราบว่าตัวอย่างสุดท้ายเชื่อมโยงกับ$c&&chop$,
แต่เริ่มส่องแสงจริงๆสำหรับการดำเนินการหลายคำสั่งส่วนใหญ่ &&
โดยทั่วไปสิ่งที่สูญเสียความสำคัญผู้ประกอบการ
use strict
อย่า (อย่าพูดถึงฉันเกี่ยวกับเรื่องนี้บริบทของ PCG.SE เป็นเรื่องสำคัญ) และที่สำคัญอย่าใช้รหัสราวกับอยู่ภายใต้ความเข้มงวด ผู้ต้องสงสัยตามปกติ:
my
ประกาศตัวแปรหากคุณสามารถหลีกเลี่ยงได้ ตัวแปรเดียวที่จำเป็นจริงๆmy
คือตัวแปรที่คุณต้องการกำหนดขอบเขต นั่นเป็นสิ่งที่แทบจะไม่เกิดขึ้นเลยเมื่อเล่นกอล์ฟซึ่งคุณไม่ต้องการการปกป้องขอบเขตและมีแนวโน้มที่จะควบคุมการเรียกซ้ำprint hello
จะไม่ทำงาน จริงๆแล้วมันหมายถึงprint hello $_
(พิมพ์$_
ไปยัง filehandle hello
)
print
และตอนนี้ฉันไม่สามารถหาตัวอย่างที่ดีและสั้นได้)
ฉันแน่ใจว่าบางส่วนของชื่อเหล่านี้มีชื่อทางการและฉันก็ไม่ทราบ
print $n++ while ($n < 10)
$var = join('',<>)
print ('X'*10) . "\n";
นานกว่าprint ('X'*10) . $/;
say
ฟังก์ชั่นของ Perl นั้นสั้นกว่าprint
แต่คุณจะต้องรันโค้ดด้วย-E
แทนที่จะเป็น-e
a..z
ถ้ามีความจำเป็นเป็นสตริงใช้aa..zz
join
$z = 'z'; print ++$z;
จะแสดงaa
นั่นคือทั้งหมดที่ฉันสามารถคิดได้ในขณะนี้ ฉันอาจเพิ่มอีกในภายหลัง
print ('X'*10) . $/;
ควรทำ สำหรับฉันมันพิมพ์0
และไม่มีการขึ้นบรรทัดใหม่ สำหรับสิ่งหนึ่งที่วงเล็บกลายเป็นข้อโต้แย้งการเรียกใช้ฟังก์ชันสไตล์ซึ่งผูกแน่นกว่าprint
.
และไม่ได้หมายความว่าคุณx
แทน*
หรืออะไร?
while
แต่join'',<>;
ก็สามารถใช้งานได้หากไม่มีวงเล็บ
ใช้$%
แทนการ$a
ช่วยให้คุณสามารถวางชื่อตัวแปรด้านขวาติดกับif
, for
หรือwhile
สร้างเช่น:
@r=(1,2,3,4,5);$%=4;
print$_*$%for@r
หลายคนสามารถใช้งานได้ แต่ตรวจสอบเอกสารและคำตอบของ @ BreadBoxที่มีเอฟเฟกต์เวทมนตร์
หากคุณไม่สามารถใช้คำสั่ง modfiers ตามคำตอบของ @ JBแผนที่อาจบันทึกไบต์:
for(@c){}
เมื่อเทียบกับ map{}@c;
และเป็นประโยชน์ถ้าคุณต้องการที่จะทำซ้ำซ้อนกันในขณะที่คุณสามารถใส่ postfix ลูปภายในfor
map
Perl มีตัวแปรเวทย์สำหรับ 'ข้อความก่อนการจับคู่' และ 'ข้อความหลังการจับคู่' ดังนั้นจึงเป็นไปได้ที่จะแบ่งออกเป็นกลุ่มที่มีอักขระน้อยกว่า:
($x,$y)=split/,/,$_;
($x,$y)=/(.+),(.+)/;
/,/; # $x=$`, $y=$'
# Note: you will need to save the variables if you'll be using more regex matches!
สิ่งนี้อาจทำงานได้ดีแทนsubstr
:
$s=substr$_,1;
/./;# $s=$'
$s=substr$_,4;
/.{4}/;# $s=$'
หากคุณต้องการเนื้อหาของการแข่งขัน$&
สามารถใช้เช่น:
# assume input like '10 PRINT "Hello, World!"'
($n,$c,$x)=split/ /,$_;
/ .+ /; # $n=$`, $c=$&, $x=$'
หากคุณโทรมาพูดprint
สี่ครั้งขึ้นไปในรหัสของคุณ (สิ่งนี้จะแตกต่างกันไปตามความยาวของรูทีนที่คุณโทร) ให้แทนที่ด้วยชื่อย่อยที่สั้นกว่า:
sub p{print@_}p;p;p;p
เมื่อเทียบกับ
print;print;print;print
หากคุณมีรหัสเช่น:
$i--if$i>0
คุณสามารถใช้ได้:
$i-=$i>0
แทนที่จะบันทึกบางไบต์
หากคุณไม่ได้กำหนดให้กับตัวแปรดังนั้นจึงไม่สามารถใช้เคล็ดลับของ breadboxคุณสามารถใช้นิพจน์0|
:
rand 25 # random float eg. 19.3560355885212
int rand 25 # random int
0|rand 25 # random int
rand 25|0 # random int
~~rand 25 # random int
เป็นที่น่าสังเกต แต่คุณไม่จำเป็นต้องใช้จำนวนเต็มเพื่อเข้าถึงดัชนีอาร์เรย์:
@letters = A..Z;
$letters[rand 26]; # random letter
redo
เพิ่มพฤติกรรมวงบล็อกโดยไม่ต้องหรือ for
เป็นวงไม่สิ้นสุดwhile
{redo}
อย่าวงเล็บฟังก์ชั่นการโทร
Perl ช่วยให้คุณเรียกใช้ฟังก์ชั่นที่รู้จักกัน (หลักหรือที่ประกาศไว้ล่วงหน้า) โดยใช้NAME LIST
ไวยากรณ์ สิ่งนี้จะช่วยให้คุณวาง&
เครื่องหมาย (ถ้าคุณยังใช้อยู่) รวมถึงวงเล็บ
ตัวอย่างเช่น: $v=join'',<>
ลองใช้ค่าของนิพจน์การกำหนดค่าเช่น:
# 14 characters
$n=pop;$o=$n&1
# 13 characters, saves 1
$o=($n=pop)&1
ใช้งานได้เพราะ$n
มี 2 ตัวอักษรใน Perl คุณสามารถเปลี่ยน$n
เป็น()
ไม่มีค่าใช้จ่ายและบันทึก 1 อัฒภาคด้วยการย้ายการกำหนดไปไว้ในวงเล็บ
คุณสามารถรันหลาย statement ที่แตกต่างกันภายในตรรกะที่ประกอบไปด้วยตรรกะสามส่วน
สมมติว่าคุณมีขนาดใหญ่if
- elsif
คำสั่ง นี่อาจเป็นเหตุผลใด ๆ และจำนวนงบใด ๆ
if( $_ < 1 ) {
$a=1;
$b=2;
$c=3;
say $a.$b.$c;
} elsif($_ < 2 ) {
$a=3;
$b=2;
$c=1;
say $a.$b.$c;
} elsif( $_ < 3) {
$a=2;
$b=2;
$c=2;
say $a.$b.$c;
}
คุณสามารถใช้(cmd1, cmd2, cmd3)
ภายในผู้ประกอบการที่ประกอบไปด้วยเพื่อเรียกใช้คำสั่งทั้งหมด
$_ < 1 ?
($a=1,$b=2,$c=3,say$a.$b.$c):
$_ < 2 ?
($a=3,$b=2,$c=1,say$a.$b.$c):
$_ < 3 ?
($a=2,$b=2,$c=2,say$a.$b.$c):
0; #put the else here if we have one
นี่เป็นตัวอย่างตัวอย่าง:
perl -nE'$_<1?($a=1,$b=2,$c=3,say$a.$b.$c):$_<2?($a=3,$b=2,$c=1,say$a.$b.$c):$_<3?($a=2,$b=2,$c=2,say$a.$b.$c):0;' <(echo 2)
select(undef,undef,undef,$timeout)
แทนTime::HiRes
(นำมาจากhttps://stackoverflow.com/a/896928/4739548 )
ความท้าทายหลายอย่างต้องการให้คุณนอนหลับด้วยความแม่นยำมากกว่าจำนวนเต็ม select()
อาร์กิวเมนต์การหมดเวลาของสามารถทำสิ่งนั้นได้
select($u,$u,$u,0.1)
มีประสิทธิภาพมากกว่า:
import Time::HiRes qw(sleep);sleep(0.1)
ตัวแรกคือเพียง 20 ไบต์ในขณะที่ตัวหลังใช้เวลาถึง 39 อย่างไรก็ตามตัวเก่าต้องการให้คุณไม่ได้ใช้งาน$u
และไม่เคยกำหนดไว้
หากคุณจะใช้มันเป็นจำนวนมากการนำเข้าTime::HiRes
จ่ายออก แต่ถ้าคุณต้องการมันเพียงครั้งเดียวการใช้select($u,$u,$u,0.1)
บันทึก 19 ไบต์ซึ่งเป็นการปรับปรุงในกรณีส่วนใหญ่
ยกเว้นกรณีที่มีการระบุเป็นอย่างอื่นคุณไม่จำเป็นต้องขึ้นบรรทัดใหม่
'ความท้าทาย' ของเราพูดว่า 'เอาท์พุทตัวเลขสุ่มจาก 0 ถึง 9 ถึง STDOUT' เราสามารถใช้รหัสนี้ (28 ไบต์):
$s=int(rand(10));print"$s\n"
และย่อให้สั้นลงถึงสิ่งนี้ (25 ไบต์):
$s=int(rand(10));print $s
เพียงพิมพ์ตัวแปร อันสุดท้ายนี้ใช้กับความท้าทายนี้โดยเฉพาะ (19 ไบต์):
print int(rand(10))
แต่จะใช้ได้เฉพาะเมื่อคุณไม่ต้องทำอะไรกับตัวแปรระหว่างการกำหนดและการพิมพ์
บางครั้ง (บ่อยครั้งเมื่อต้องรับมือกับความท้าทายควินินหรือจำกัด แหล่งที่มา ) คุณได้รับประโยชน์อย่างมากจากความสามารถในการซ้อนตัวอักษรสตริง q(…)
ปกติคุณต้องการทำเช่นนี้กับ อย่างไรก็ตามขึ้นอยู่กับอักขระที่คุณต้องการภายในสตริงคุณอาจบันทึกไบต์และใช้<…>
ตัวดำเนินการ glob (โปรดทราบว่าสิ่งที่อยู่ในวงเล็บเหลี่ยมไม่สามารถดูเหมือนไฟล์แฮนเดิลและไม่สามารถดูเหมือนจะขยายเข้าไปในรายการชื่อไฟล์ซึ่งหมายความว่าอักขระจำนวนมากจะไม่ทำงานอย่างถูกต้อง)
ภาพประกอบที่มีคุณค่าของการทำตามนี้คือรหัสการสร้างการป้อนข้อมูลลงในคลื่นไซน์:
s/./print" "x(sin($i+=.5)*5+5).$&/eg;
อย่างที่คุณเห็นมันค่อนข้างกะทัดรัดในการวนซ้ำอักขระในอินพุตมาตรฐาน คุณสามารถใช้ regex อื่นเพื่อเปลี่ยนวิธีการจับคู่สิ่งต่าง ๆ
$_=print""
$_=print$foo
จะสั้นกว่า