เคล็ดลับสำหรับการเล่นกอล์ฟใน PHP


37

คุณมีเคล็ดลับทั่วไปสำหรับการเล่นกอล์ฟใน PHP หรือไม่? ฉันกำลังมองหาแนวคิดที่สามารถนำไปใช้กับปัญหารหัสกอล์ฟโดยทั่วไปซึ่งอย่างน้อยค่อนข้างเฉพาะกับ PHP (เช่น "ลบความคิดเห็น" ไม่ใช่คำตอบ) กรุณาโพสต์หนึ่งเคล็ดลับต่อคำตอบ


เดี๋ยวก่อนฉันกำลังทำอยู่ใช่ไหม? ... อย่างไรก็ตามฉันอยากรู้เกี่ยวกับอันนี้จริงๆ PHP ถูกใช้โดยคนจำนวนมากและนักกอล์ฟ แต่ฉันแทบไม่รู้เลยว่าจะต้องใช้รหัส PHP กับกอล์ฟอย่างไร
— JiminP

ใช้แท็กสั้น ๆ <??> มันสามารถบันทึกไม่กี่ไบต์
— ม็อบ

คำตอบ:


22

ทำความเข้าใจว่าตัวแปรและช่องว่างโต้ตอบกับภาษาของ PHP สร้างได้อย่างไร

ในการตีกอล์ฟเวลาสั้น ๆ ของฉันฉันพบว่าภาษาของ PHP สร้างขึ้น (เช่น echo, return, for, while และ etc) ทำงานในลักษณะที่ไม่ค่อยมีสัญชาตญาณเมื่อโต้ตอบกับตัวแปรและช่องว่าง

echo$v;ตัวอย่างเช่นถูกต้องสมบูรณ์ตามที่เป็นอยู่return$v;และโครงสร้างที่คล้ายกันอื่น ๆ การลดช่องว่างขนาดเล็กเหล่านี้อาจนำไปสู่การลดลงของระยะเวลาสะสมที่สำคัญ

อย่างไรก็ตามโปรดทราบว่าตัวแปรก่อนการสร้างภาษาต้องใช้ช่องว่างหลังในตัวอย่างต่อไปนี้:

foreach($a AS$b){}

เนื่องจากASเป็นการสร้างภาษาจึงไม่จำเป็นต้องใช้ช่องว่างก่อนตัวแปร$bแต่หากมีการเว้นช่องว่างไว้ก่อนหน้าจะทำให้เกิดการ$aASแยกส่วนนี้เป็นชื่อตัวแปรและนำไปสู่ข้อผิดพลาดทางไวยากรณ์


3
foreach($a[1]as$b)ไม่ต้องการพื้นที่สีขาว สิ่งนี้ไม่ได้เกี่ยวกับการสร้างภาษาและตัวแปร แต่เกี่ยวกับช่องว่างระหว่างตัวอักษรของคำที่แตกต่างกัน
— ติตัส

1
อินสแตนซ์อื่นที่คุณต้องการช่องว่างอยู่ในการต่อสายอักขระ ยกตัวอย่างเช่นecho $a+5." text"จะไม่ทำงานเพราะ PHP คิดว่าเป็นจุดทศนิยมสำหรับ. 5เพื่อให้มันใช้งานได้คุณจะต้องเพิ่มพื้นที่เช่นนี้:echo $a+5 ." text"
— Business Cat

@BasicSunset echo$a+5," text";ว่าคำสั่งสามารถเขียนเป็น echoสร้างช่วยให้คุณสามารถส่งผ่านพารามิเตอร์หลาย ที่หนึ่งจะต้องมีการเขียนคุณสามารถเขียนecho"result: ".($a+5)."!"; echo"result: ",$a+5,"!";ในความเป็นจริงการส่งพารามิเตอร์หลายตัวไปยังechoa เป็นการปรับให้เหมาะสมขนาดเล็กเนื่องจากโค้ดจะทำงานเร็วขึ้นเล็กน้อย (เนื่องจากคุณไม่ได้ต่อผลลัพธ์เอาไว้ แต่ส่งแยกต่างหาก) สำหรับความท้าทายเกี่ยวกับการเขียนโค้ดที่เร็วที่สุดนี่อาจช่วยนิด ๆ หน่อย ๆ
— Ismael Miguel

@IsmaelMiguel จะทำงานร่วมกับechoแต่ไม่ได้มีprint(ที่คุณต้องการหากคุณใส่ไว้ในการแสดงออก: echoเป็นโครงสร้างบริสุทธิ์ที่มีค่าตอบแทนในขณะที่print สามารถทำหน้าที่เป็นฟังก์ชั่น: มันไม่จำเป็นต้องมีวงเล็บ แต่มักกลับมาเสมอint(1).
— ติตัส

@Titus printผมไม่ได้พูดอะไรเกี่ยวกับ
— Ismael Miguel

22

ใช้สตริงอย่างชาญฉลาด

คำตอบนี้เป็นสองเท่า ส่วนแรกคือเมื่อประกาศสตริงคุณสามารถใช้การแปลงค่าคงที่ที่ไม่รู้จักของ PHP เป็นค่าสตริงเพื่อประหยัดพื้นที่เช่น:

@$s=string;

@เป็นสิ่งจำเป็นที่จะแทนที่คำเตือนนี้จะผลิต โดยรวมแล้วคุณจะจบลงด้วยการลดหนึ่งตัวอักษร

คือบางครั้งอาจเป็นพื้นที่ที่มีประสิทธิภาพในการตั้งค่าตัวแปรเป็นชื่อของฟังก์ชันที่ใช้บ่อย โดยปกติคุณอาจมี:

preg_match(..);preg_match(..);

แต่เมื่อเล่นกอล์ฟสิ่งนี้สามารถย่อให้ง่ายต่อการ:

@$p=preg_match;$p(..);$p(..);

ด้วย "preg_match" เพียงสองอินสแตนซ์คุณจะบันทึกอักขระได้เพียงตัวเดียว แต่ยิ่งคุณใช้ฟังก์ชั่นมากเท่าไหร่คุณก็จะประหยัดพื้นที่ได้มากขึ้นเท่านั้น


10
@ ไม่จำเป็นใน codegolf; ประกาศและคำเตือน (รวมถึงE_DEPRECATED) เป็นที่ยอมรับ
— ติตัส

3
@Titus แต่ใน PHP คำเตือนจะส่งออกไปยังไฟล์มาตรฐานดังนั้นจึงจำเป็น
— brianush1

1
@Titus ฉันเชื่อว่าคุณสามารถระงับพวกเขาในphp.iniไฟล์
— Stan Strum

12

คุณไม่จำเป็นต้องเขียนเช็คตามเงื่อนไขทุกครั้ง ตัวอย่างเช่นเฟรมเวิร์กบางตัวใช้สิ่งนี้ที่ด้านบนของไฟล์เพื่อบล็อกการเข้าถึง:

<?php defined('BASE_PATH')||die('not allowed');

หรือในฟังก์ชั่นปกติ

$value && run_this();

แทน

if($value) { run_this(); }

สามารถใช้งานได้กับ JS
— ЕвгенийНовиков

8

ใช้ไวยากรณ์อาร์เรย์แบบสั้น

ตั้งแต่ PHP 5.4 อาร์เรย์สามารถประกาศได้โดยใช้วงเล็บเหลี่ยม (เช่นเดียวกับ JavaScript) แทนที่จะใช้array()ฟังก์ชัน:

$arr=['foo','bar','baz'];
// instead of
$arr=array('foo','bar','baz');

มันจะประหยัดห้าไบต์


แต่อาจมีค่าใช้จ่ายเป็นไบต์หากคุณมี "หลุม" ในอาเรย์แบบเชื่อมโยง:

$arr=array(,1,,3,,5);
// is one byte shorter than
$arr=[1=>1,3=>3,5=>5];

ข้อเสียจะกระทบกันเล็กน้อยในภายหลังหากคุณสามารถเติมค่า "ว่าง" ในรูได้:

$arr=[0,1,0,3,0,5,0,7,0,9,10,11];
// costs two byte more than
$arr=array(,1,,3,,5,,7,,9,,11);

2
PHP 7.1 ยังแนะนำการกำหนดรายชื่อสั้น ๆ[,$a,$b,$c]=$argv;:
— ติตัส

7

ใช้ $ {0}, $ {1}, $ {2}, ... แทนที่จะเป็น $ a [0], $ a [1], $ a [2], ...

ถ้าคุณกำลังดำเนินการจัดการอาร์เรย์อ้างอิงมากที่สุดที่จะเป็นดัชนีอาร์เรย์สามารถถูกแทนที่ด้วยเพียง$a[$i] $$iสิ่งนี้จะเป็นจริงถ้าดัชนีเป็นจำนวนเต็มเนื่องจากจำนวนเต็มเป็นชื่อตัวแปรที่ถูกต้องใน PHP (แม้ว่าตัวอักษรจะต้องใช้เครื่องหมายวงเล็บเช่น${0})

พิจารณาการนำไปใช้ของเดือย Rabonowitz Wagon:

3.<?for(;$g?$d=0|($a[$g]=$d*$g--/2+($a[$g]?:2)%$g*1e4)/$g--:238<<printf($e?'%04d':'',$e+$d/$g=1e4)^$e=$d%$g;);

สิ่งนี้สามารถปรับปรุงได้ 6 ไบต์เพียงแค่แทนที่การอ้างอิงอาร์เรย์ทั้งสอง$a[$g]ด้วย$$g:

3.<?for(;$g?$d=0|($$g=$d*$g--/2+($$g?:2)%$g*1e4)/$g--:238<<printf($e?'%04d':'',$e+$d/$g=1e4)^$e=$d%$g;);

1
ผมบันทึกไว้เพียง 3 ไบต์กับ: ตู้โชว์
— ติตัส

6

เรียนรู้เป็นกลุ่มย่อยที่มีขนาดใหญ่ของการทำงานห้องสมุด

ห้องสมุดของ PHP นั้นค่อนข้างใหญ่และมีฟังก์ชั่นการใช้งานที่สะดวกมากมาย คุณสามารถค้นหาได้ทุกครั้งที่คุณพยายามทำบางสิ่ง แต่คุณจะไม่พบสิ่งที่ตรงกับการค้นหาของคุณ วิธีที่ดีที่สุดคือทำความคุ้นเคยกับไลบรารีและจดจำชื่อฟังก์ชันและสิ่งที่พวกเขาทำ


6
นั่นเป็นความทรงจำมากมายโดยเฉพาะอย่างยิ่งเมื่อมีการตั้งชื่อฟังก์ชั่นมากมาย ;-) ค่อนข้างมาก
— Joey

@ ตกลงเห็นด้วย คล้ายกับการจำไลบรารี Java ยกเว้นว่าจะมีประโยชน์น้อยกว่าเนื่องจากเป็น verbose มากกว่า
— Matthew อ่าน

3
ฉันพบว่าฟังก์ชั่นที่สำคัญที่สุดสำหรับความท้าทายที่ฉันได้พบที่นี่คือฟังก์ชั่นการจัดการสตริงและการจัดการอาร์เรย์ ใช้ความคิดสร้างสรรค์ของผู้ที่สามารถลดรหัส
— migimaru

6

ฟังก์ชั่นที่กำลังทำงานอยู่ภายในสตริง

ลองสิ่งนี้:

$a='strlen';
echo "This text has {$a('15')} chars";

หรือลองสิ่งนี้:

//only php>=5.3
$if=function($c,$t,$f){return$c?$t:$f;};
echo <<<HEREDOCS
    Heredocs can{$if(true,' be','not be')} used too and can{$if(<<<BE
{$if(true,1,0)}
BE
,'','not')} be nested
HEREDOCS;
//Expected output: Heredocs can be used too and can be nested

ใช้งานได้กับสตริงที่ใช้""และ heredocs เท่านั้น (ไม่ต้องสับสนกับ nowdocs)

การใช้ฟังก์ชั่นที่ซ้อนกันเป็นไปได้เฉพาะภายใน heredocs ที่ซ้อนกัน (หรือคุณจะพบข้อผิดพลาดในการแยกวิเคราะห์)!


you will run into parse errorsฉันอ่านเองไม่ได้เหรอ? เครื่องยนต์ Zend ที่น่ารำคาญทำอย่างไรกัน
— Stan Strum

ครั้งต่อไปที่ฉันใช้อาร์กิวเมนต์"PHP เป็นภาษาโปรแกรมที่ดี"ฉันจะใช้สิ่งนี้เป็นจุดตอบโต้ ว้าว.
— primo

@primo มันไม่ดีเหรอ? : O
— Ismael Miguel

5

สนุกกับ typecasts

  • !!$fooจะเปลี่ยนค่าความจริงใด ๆ เป็นtrue(หรือ1ในเอาต์พุต), ค่าเท็จ (0, สตริงว่าง, อาร์เรย์ว่าง) เป็นfalse(หรือเอาต์พุตว่าง)
    สิ่งนี้ไม่ค่อยจำเป็นสำหรับโค้ดกอล์ฟในกรณีส่วนใหญ่ที่คุณต้องการบูลีน บล็อกโดยนัย

  • (int)$fooสามารถเขียนเป็น$foo|0หรือfoo^0แต่อาจต้องการวงเล็บ
    สำหรับ booleans และสายอักขระ$foo*1หรือ+$fooสามารถใช้เพื่อส่งไปยัง int

  • แตกต่างจากภาษาอื่น ๆ ส่วนใหญ่ PHP จัดการสตริงที่มีค่าตัวเลขเป็นตัวเลข ดังนั้นหากคุณมีสตริงใด ๆ ที่มีตัวเลขที่คุณต้องคำนวณด้วยเพียงแค่คำนวณ
  • วิธีอื่น ๆ ที่ไม่ได้ทำงาน: การคูณจำนวนใด ๆ ในตัวแปรที่มี10คุณสามารถผนวกศูนย์: ->*10 .0แต่ในกรณีนี้ PHP จะใช้จุดเป็นทศนิยมและบ่น (มันแตกต่างกันแม้ว่าคุณจะมีจำนวนศูนย์เป็นจำนวนตัวแปรในสตริง)
  • หากต้องการเปิดอาร์เรย์เป็นสตริงใช้แทนjoin หากคุณไม่ต้องการตัวคั่นห้ามใช้: ทำเช่นเดียวกับimplode
    join($a)join('',$a)
  • Incrementing สตริง: คุณลักษณะที่น่าตื่นตาตื่นใจที่สุด IMO คือการที่ผลิต$s=a;$s++; $s=b;ใช้ได้กับอักขระตัวพิมพ์ใหญ่และตัวพิมพ์เล็ก ผลในการ$s=Z;$s++; นี้ยังทำงานร่วมกับกรณีผสม: การ, การ, การและการ การลดลงใช้ไม่ได้กับสตริง (และไม่ได้เปิดอยู่) ย้อนกลับไปใน PHP 3 ผลิต ฉันเสียใจเล็กน้อยที่พวกเขานำสิ่งนั้นออก$s=AA;
    aZbAA1A2A9B0z99Zaa00A
    NULL
    $n="001";$n++;$n="002";

ไม่ว่าคุณจะเล่นกอล์ฟอะไร: มีโต๊ะที่ให้ความสำคัญกับมือเสมอ


4

ใช้แท็กทางลัด

ในรหัสปกติก็ปฏิบัติที่ดีในการใช้งานและ<?php ?>อย่างไรก็ตามนี่ไม่ใช่รหัสปกติ - คุณกำลังเขียนรหัสกอล์ฟ แทนการเขียน<?php <?แทนการเขียน<?php echo <?=อย่าพิมพ์?>ตอนท้าย - เป็นทางเลือกที่สมบูรณ์ ถ้าคุณต้องการ?>ด้วยเหตุผลบางอย่าง (ตัวอย่างเช่นในการส่งข้อความและมันสั้นลงหรืออย่างใดอย่างหนึ่งไม่ต้องใส่เครื่องหมายอัฒภาคก่อนหน้า - ไม่จำเป็นต้องใช้ตาม?>ความหมายอัฒภาค

ผิด (ยาวเกินไปแน่นอน):

<?php echo ucfirst(trim(fgets(STDIN)));?>s!

แก้ไข:

<?=ucfirst(trim(fgets(STDIN)))?>s!

ด้วยการ-rตั้งค่าสถานะ ( ซึ่งมาฟรี ) คุณไม่แม้แต่แท็กใด ๆ เลย (และคุณไม่ได้รับอนุญาตให้ใช้)
— ติตัส

4

วนลูปผ่านสตริง

สามารถทำได้ด้วย 26 ไบต์หรือ 24 ลงไปที่ 18:

foreach(str_split($s)as$c)  # A) 26 - general
for($p=0;a&$c=$s[$p++];)    # B) 24 - general
for($p=0;$c=$s[$p++];)      # C) 22 - if $s has no `0` character
for(;a&$c=$s[$p++];)        # D) 20 - if $p is already NULL or 0 (does NOT work for false)
for(;$c=$s[$p++];)          # E) 18 - both C and D

for(;$o=ord($s[$p++]);)     # F) 23 - work on ASCII codes, if $s has no NULL byte and D
for(;~$c=$s[$p++];)         # G) 19 - if $s has no chr(207) and D

$a&$bไม่ได้ค่าที่เหมาะสมและใน (รหัส ASCII ของ) ตัวละครใน$aและ$b
และผลในสตริงที่มีความยาวเช่นเดียวกับที่สั้นกว่าของและ$a$b


คุณช่วยเพิ่มord($s[$p++])ทางเลือกให้for(;$s+=ord($argv[++$i])%32?:die($s==100););กับfor(;$c=$argv[++$i];)$s+=ord($c)%32;echo$s==100;คำถามนี้ได้ที่codegolf.stackexchange.com/questions/116933/…
— JörgHülsermann

โปรดเพิ่ม~สำหรับกรณีที่คุณทำงานกับตัวเลขเท่านั้น
— JörgHülsermann

โปรดทราบว่า PHP 7.2 ให้คำเตือนเกี่ยวกับ~$cวิธีการ
— ติตัส

4

ใช้ผู้ประกอบการที่ประกอบไปด้วย

if(a==2){some code;}else{some other code;}

สามารถย่อไปนี้:

(a==2?some code:some other code);

สั้นลงเหรอ


“ ชวเลขที่มีเงื่อนไข”? บอกชื่อจริงได้ดีกว่าดังนั้นผู้ที่สนใจรายละเอียดเพิ่มเติมสามารถค้นหาได้ในเอกสารประกอบการ: ผู้ประกอบการที่ประกอบไปด้วยส่วนที่สาม
— จัดการ

3
คำถามถามถึงเคล็ดลับที่ค่อนข้างเฉพาะเจาะจงกับ PHP นี้เป็นหนึ่งรวมอยู่ในเคล็ดลับสำหรับทุกภาษา
— Peter Taylor

3
ผู้ประกอบการที่ประกอบไปด้วยมีพฤติกรรมแปลก ๆ ใน PHP ถ้าคุณทำมัน a?aa:ab?aba:abb:bประเมิน(a?aa:ab)?(aba):(abb)หรืออะไรทำนองนั้น
— ติตัส

1
และเริ่มต้นด้วย PHP 5.3 คุณสามารถละเว้นผู้ประกอบการที่สองเป็นเช่นเดียวกับ$a?:$b $a?$a:$b
— ติตัส

1
@Cyoce ปลดล็อก||เพื่อบูลีนใน PHP
— ติตัส

3

ด้วยชื่ออื่น ... ฟังก์ชั่นสมนาม

ใช้ ...

  • join แทน implode
  • chopแทนrtrim( chopใน PERL แตกต่างกัน!)
  • die แทน exit
  • fputs แทน fwrite
  • is_intแทนis_integerหรือis_long
  • is_realแทนis_floatหรือis_double
  • key_exists แทน array_key_exists
  • mysql แทน mysql_db_query

... เพื่อตั้งชื่อนามแฝงที่สำคัญที่สุด ลองดูที่http://php.net/aliasesสำหรับข้อมูลเพิ่มเติม


โอ้ ... และคุณรู้หรือไม่ว่าการdieทำงานกับและไม่มีพารามิเตอร์? die(1)จะออกจากโปรแกรมด้วยรหัสข้อผิดพลาด1(ไม่แน่ใจในเรื่องนี้อย่างสมบูรณ์ต้องการการทดสอบ); dieจะออกด้วยรหัส0และdie("Hello")จะออกด้วยรหัสหลังจากการพิมพ์0 Hello
— ติตัส

3

อาร์เรย์ที่เชื่อมโยงสามารถรวมเข้ากับตัว+ดำเนินการได้

แทน:

$merged = array_merge($a, $b);

ใช้:

$merged = $a + $b;

หมายเหตุตัว+ดำเนินการทำงานกับอาร์เรย์ที่มีการจัดทำดัชนีเช่นกัน แต่อาจไม่ทำสิ่งที่คุณต้องการ


อันที่จริงแล้วการทดแทนที่ดีมักจะไม่เหมือนกัน: pastebin.com/seYeaP38
— จัดการ

อ่าใช่แล้วฉันมีชื่อเดิมว่า "อาเรย์แบบเชื่อมโยง ... " แล้วจึงลบออก ฉันจะอธิบายอย่างชัดเจนขอบคุณ
— Alex Howansky

อาร์เรย์ตัวเลขสามารถผสานโดยใช้+ตราบใดที่ดัชนีนั้นแตกต่างกัน หากไม่เป็นเช่นนั้นค่าจากอาร์เรย์แรกจะถูกเขียนทับด้วยค่าจากอาร์เรย์ที่สอง (เช่นเดียวกับ array_merge) ความแตกต่าง: +ไม่เรียงลำดับดัชนีใหม่
— ติตัส

3

array_flip vs array_search

ใช้

array_flip($array)[$value]

แทน

array_search($value,$array)

เพื่อบันทึก 1 ไบต์ในอาร์เรย์ที่การเกิดขึ้นของแต่ละค่าไม่ซ้ำกัน


3

ข้อเท็จจริงที่น่าสนใจบางประการเกี่ยวกับตัวแปรตัวแปร

ฉันต้องแชร์พวกเขา (ก่อนที่ฉันจะตรวจสอบว่าอย่างน้อยหนึ่งในนั้นช่วยเล่นกอล์ฟ):

  • ใช้ตัวอักษร: $x=a;$$x=1;$x++;$$x=2;echo"$a,$b";พิมพ์1,2
    แต่การดำเนินการทางคณิตศาสตร์อื่น ๆ ใช้ไม่ได้กับตัวอักษร
  • ในฐานะที่เป็นพรีโม่กล่าวก่อนหน้านี้คุณสามารถใช้หมายเลขบริสุทธิ์เป็นชื่อตัวแปร: พิมพ์
    $a=1;$$a=5;$a++;$$a=4;${++$a}=3;echo${1},${2},${3};543
  • คุณสามารถไม่เพียงใช้[0-9a-zA-Z_]สำหรับชื่อตัวแปร แต่ทุกสตริง: พิมพ์
    $x="Hello!";$$x="Goodbye.";echo${"Hello!"};Goodbye.
  • แต่: ทุกอย่างยกเว้น[a-zA-Z_][a-zA-Z_0-9]*ชื่อตัวแปรต้องใช้เครื่องหมายปีกกาสำหรับการใช้ตัวอักษร
  • กับตัวแปรไม่มีกำหนด$$x=1ชุด${NULL}ซึ่งเป็นเช่นเดียวกับและ ${false}${""}
  • $a=1;$$a=5;ไม่ได้ตั้งค่าเพียงแต่ยัง${1}${true}

  • อีกหนึ่งที่แปลกประหลาดหนึ่งฉันได้พบจนถึงขณะนี้: $a=[];$$a=3;echo${[]};ลอง ใช่มันพิมพ์3!

เหตุผลส่วนใหญ่: ชื่อตัวแปรจะถูกประเมินเป็นสตริงเสมอ
(ขอบคุณ @Christoph สำหรับการชี้ให้เห็น)
ดังนั้นอะไรก็ตามที่คุณได้รับเมื่อคุณprintหรือechoนิพจน์นั่นคือสิ่งที่คุณได้รับในชื่อตัวแปร


1
ชื่อตัวแปรถูกแปลงเป็นสตริงที่อธิบายสามจุดสุดท้ายในรายการของคุณ []แปรรูปArray: พิมพ์${[]} = 5;echo $Array; 5ฉันค่อนข้างแน่ใจว่าคุณรู้ว่า แต่ทุกคนอาจไม่เห็นชัดเจน :)
— Christoph

@ เจฟฟ์ฉันคงคำผิด ขอบคุณที่สังเกต
— ติตัส

2

การขึ้นบรรทัดใหม่
ถ้าเอาต์พุตต้องการการแบ่งบรรทัดใช้ตัวแบ่งบรรทัดแบบฟิสิคัล (1 ไบต์) แทน"\n"
นี่จะช่วยให้คุณได้รับประโยชน์จากการเลือกระหว่างเครื่องหมายคำพูดเดี่ยวและคู่


2

หลีกเลี่ยงคำพูดที่เป็นไปได้

PHP ใช้คำที่ไม่รู้จักในสตริงตามตัวอักษรโดยปริยาย

$foo=foo;เหมือนกับ$foo='foo';(สมมติว่าfooไม่ใช่คำสำคัญหรือค่าคงที่ที่กำหนด): $foo=echo;ใช้งานไม่ได้

แต่: $p=str_pad;ไม่; และประเมิน$p(ab,3,c)abc

การใช้ตัวอักษรสตริงโดยไม่มีเครื่องหมายอัญประกาศจะทำให้ได้รับการแจ้งเตือนสำหรับUse of undefined constant; แต่นั่นจะไม่แสดงหากคุณใช้ค่าเริ่มต้นสำหรับerror_reporting(พารามิเตอร์ CLI -n)


ผมเพิ่งสังเกตเห็น: คำตอบนี้เป็นขยายค่อนข้าง / ซ้ำปรับปรุงของcodegolf.stackexchange.com/a/2916/55735
— ติตัส

หมายเหตุ: PHP ก่อนหน้า 7.2 ให้การบอกกล่าว (ซึ่งคุณสามารถ opress พร้อมกับ-nflag); 7.2 ผลผลิตคำเตือน; รุ่นที่ใหม่กว่าจะโยนข้อผิดพลาด!
— ติตัส

2

ฟังก์ชั่นลูกศรใน PHP 7.4

PHP 7.4 ใช้เวอร์ชั่น RC2 แล้วและหวังว่าจะเปิดตัวในอีกประมาณ 2 เดือน รายการคุณลักษณะใหม่อยู่ที่นี่ (หน้านี้สามารถปรับปรุงได้จริงเมื่อมีการออก 7.4) ใน 7.4 ในที่สุด PHP ก็มีฟังก์ชั่นลูกศรดังนั้นไม่เพียง แต่คำตอบของฟังก์ชั่นจะสั้นลงเท่านั้น นี่คือตัวอย่างบางส่วน:

ส่งคืนอินพุต + 1:

ฟังก์ชั่นไม่ระบุชื่อ (ปิด) - 25 ไบต์ - ลองออนไลน์!

function($n){return$n+1;}

ฟังก์ชั่นลูกศร - 12 ไบต์ - ลองออนไลน์!

fn($n)=>$n+1

ทวีคูณรายการของอินพุตแรก (อาร์เรย์ของ ints) โดยอินพุตที่สอง (int):

ฟังก์ชั่นไม่ระบุชื่อ (ปิด) - 72 ไบต์ - ลองออนไลน์!

function($a,$n){return array_map(function($b)use($n){return$b*$n;},$a);}

ฟังก์ชั่นลูกศร - 38 ไบต์ - ลองออนไลน์!

fn($a,$n)=>array_map(fn($b)=>$b*$n,$a)

คุณสังเกตเห็นว่า$nสามารถเข้าถึงได้ในฟังก์ชั่นด้านในโดยไม่มีuse $nคำสั่ง? ใช่ว่าเป็นหนึ่งในคุณสมบัติฟังก์ชั่นลูกศร


เป็นหมายเหตุด้านข้างฉันไม่สามารถรับฟังก์ชั่นลูกศรซ้ำได้ (เรียกใช้ฟังก์ชันลูกศรเดียวกันภายในตัวเอง) เพราะเราไม่สามารถตั้งชื่อให้พวกเขาและเก็บไว้เป็นตัวแปรในแบบที่$fไม่$fสามารถเข้าถึงได้ด้วยตัวเอง (เศร้า ) ดังนั้นตัวอย่างนี้ใช้งานไม่ได้และใช้$fในบรรทัดแรกทำให้เกิดข้อผิดพลาดร้ายแรง:

$f=fn($n)=>$n?$f($n-1):0;
$f(5); // Causes error: "PHP Notice: Undefined variable: f" + "PHP Fatal error: Uncaught Error: Function name must be a string"

แต่การเรียกฟังก์ชั่นลูกศรพร้อมกับฟังก์ชั่นลูกศรที่แตกต่างกันทำงาน:

$f1=fn($n)=>$n+1;
$f2=fn($n)=>$f1($n-1);
$f1(2) // Returns 3
$f2(2) // Returns 2

เกิดอะไรขึ้นถ้า$f=fn($n)=>$n?$f($n-1):0;คุณทำแทน$f=$F=fn($n)=>$n?$F($n-1):0;? มันจะใช้ได้ไหม แล้วคุณก็โทร$(5)ตามปกติ
— Ismael Miguel

@IsmaelMiguel ดูเหมือนว่าจะยังคงมีข้อผิดพลาดเดียวกัน คุณสามารถลองtio.run # phpด้วยตัวคุณเองได้เพราะ Dennis ได้อัพเดท PHP เป็น 7.4 RC2 สักครู่
— Night2

ไม่สามารถใช้งานได้ ดูเหมือนว่าจะมีเพียงตัวแปรที่กำหนดไว้ก่อนหน้านี้เท่านั้น
— Ismael Miguel


1

อาร์เรย์ที่อ้างถึงโดยตรงถูกส่งคืนจากฟังก์ชัน

เช่นแทนที่จะเป็น:

$a = foo();
echo $a[$n];

คุณทำได้:

echo foo()[$n];

วิธีนี้ใช้ได้กับ:

echo $obj->foo()[$n];

คุณยังสามารถอ่านการประกาศอาเรย์โดยตรงได้อีกด้วย:

echo [1, 2, 3, 4, 5][$n];

1

ใช้end()แทนarray_pop()

end()ฟังก์ชั่นไม่เพียง แต่ย้ายตัวชี้ภายในปลายแถวก็ยังส่งกลับค่าที่ผ่านมา หมายเหตุแน่นอนว่ามันไม่ได้ลบarray_pop()ค่าที่ดังนั้นหากคุณไม่สนใจสิ่งที่อาร์เรย์มีหลังจากนั้นคุณสามารถใช้มันแทน


1

double array_flip กับ in_array เทียบกับ array_unique

ในกรณีพิเศษนี้ array_flip สองเท่าจะบันทึก 10 ไบต์

($f=array_flip)($k=$f($c)))ลบค่าสองเท่าทั้งหมดในอาร์เรย์และฉันทำสิ่งนี้ทิ้ง$c=[],แล้ว|in_array($o,$c)แทนที่array_keys($c)ด้วย$k

for([,$x,$y]=$argv;a&$o=$y[$i];$i++)
$x[$i]==$o?:$c[$x[$i]]=$o; # if char string 1 not equal char string 2 set key=char1 value=char2
echo strtr($x,($f=array_flip)($k=$f($c)))==$y # boolean replacement string 1 equal to string 2
    ?join($k)." ".join($c) # output for true cases
:0; #Output false cases

เวอร์ชั่นออนไลน์

ต่อต้าน

for($c=[],[,$x,$y]=$argv;a&$o=$y[$i];$i++)
  $x[$i]==$o|in_array($o,$c)?:$c[$x[$i]]=$o; # if char string 1 not equal char string 2 set key=char1 value=char2
echo strtr($x,$c)==$y # boolean replacement string 1 equal to string 2
  ?join(array_keys($c))." ".join($c) # output for true cases
  :0; #Output false cases

เวอร์ชั่นออนไลน์

เทียบกับ array_unique จะช่วยประหยัด 2 ไบต์

for([,$x,$y]=$argv;a&$o=$y[$i];$i++)
  $x[$i]==$o?:$c[$x[$i]]=$o; # if char string 1 not equal char string 2 set key=char1 value=char2
echo strtr($x,array_unique($c))==$y # boolean replacement string 1 equal to string 2
  ?join(array_keys($c))." ".join($c) # output for true cases
  :0; #Output false cases

เวอร์ชั่นออนไลน์

หลังจากพบข้อผิดพลาดในโปรแกรมนี้และทดแทน$x[$i]==$o?:$c[$x[$i]]=$oการ($p=$x[$i])==$o?:$k[$c[$p]=$o]=$parray_flip คู่ก็ไม่จำเป็นอีกต่อไป


array_uniqueปลอดภัยเชื่อมโยง เย้!
— ติตัส

@Titus ฉันได้เพิ่มข้อเสนอแนะของคุณ
— JörgHülsermann

1

การตัดกันสตริง

คุณเคยใช้
join("DELIMITER",str_split($s))(31 ไบต์) หรือแม้กระทั่ง
preg_replace(".","DELIMITER",$s)(32 ไบต์)
?

มีตัวสำหรับ:

ลองchunk_split($s,1,"DELIMITER")(29 ไบต์)


หากคุณไม่ใช้พารามิเตอร์ที่สามchunk_splitจะใช้\r\n; ที่สามารถช่วยคุณประหยัด 7 หรือ 8 ไบต์

แต่ระวัง: chunk_splitเพิ่มตัวคั่นต่อท้ายสตริง
ดังนั้นคุณอาจไม่ได้สิ่งที่ต้องการ

(หากคุณไม่ได้ให้ความยาวก้อนมันจะใช้ 76. ค่อนข้างแปลกสำหรับรหัสกอล์ฟ แต่ใครจะรู้)


บางทีคุณควรเพิ่มตัวอย่างร่วมกับstrtrฉันชอบความคิดนี้
— JörgHülsermann

1

unset () และ INF

ในกรณีที่ค้นหาขั้นต่ำในอาร์เรย์คุณสามารถใช้แทน

unset($var[$k]);

$var[$k]=INF;

เพื่อบันทึก 3 ไบต์


1

str_repeat

ในบางกรณีคุณมีอินพุตของตัวละครและคุณควรเอาท์พุทพวกเขาซ้ำแล้วซ้ำอีกด้วยการป้อนข้อมูลที่เป็นศูนย์สำหรับแต่ละตัว

for(;--$z?:($c=$argn[$i++]).$z=$argn[$i++];)echo$c;

(52 ไบต์) สั้นกว่า

for(;~$c=$argn[$i++];)echo str_repeat($c,$argn[$i++]);

หรือ

for(;~$c=$argn[$i++];)echo str_pad($c,$argn[$i++],$c);

(54 ไบต์ต่อคน)

มันทำงานอย่างไรสำหรับอินพุทตัวอย่าง a1b2c1

$zไม่ได้ตั้งค่า (โดยนัยNULL) --$zไม่ทำอะไรเลยและเป็นเท็จ

$c="a", $z="1"และ$i=2-> $c.$z="a1"เป็น truthy -> เอาท์พุท"a"

--$z=0; ดังนั้นเราจึงตั้ง$c="b", $z="2"(และ$i=4) -> $c.$z="b2"เป็น truthy -> เอาท์พุท"ab"

--$z=1 -> เอาท์พุท "abb"

--$z=0; ดังนั้นเราจึงตั้งค่า$c="c"และ$z=1 $c.$z="c1"เป็นผลลัพธ์ที่แท้จริง"abbc"

--$z=0ดังนั้น$c=""และ$z=""-> $c.$z=""เป็น falsy -> แบ่งห่วง


1

การรวมforลูป

สมมติว่าคุณมีรหัสของแบบฟอร์มต่อไปนี้:

for($pre1; $cond1; $post1) for($pre2; $cond2; $post2) $code;

โดยทั่วไปสามารถรีดซ้ำได้ในแบบฟอร์มต่อไปนี้:

for($pre1; $cond2 • $post2 || $cond1 • $pre2 • $post1; ) $code;

โดยที่•หมายถึงโอเปอเรเตอร์การรวมทั่วไป ซึ่งมักส่งผลให้การนับไบต์ลดลง แต่มีแนวโน้มว่าจะต้องใช้ความคิดสร้างสรรค์ $cond2จะต้องมีการเขียนเพื่อที่จะล้มเหลวในครั้งแรกที่ผ่าน $post1ควรล้มเหลวในการดำเนินการในครั้งแรกแม้ว่ามันอาจจะง่ายกว่าในการปรับโครงสร้างใหม่ล่วงหน้าเพื่อ$post1ไม่ให้มีอยู่

หากคุณกำลังทำงานกับลูปซ้อนกันสามวงขึ้นไปคุณสามารถรวมสองวงแรกแล้วรวมเข้าด้วยกันเป็นวงอื่น ๆ ฉันพบว่ามันง่ายกว่าที่จะรวมจากภายในสู่ภายนอก


เป็นตัวอย่างให้พิจารณาวิธีแก้ปัญหาต่อไปนี้กับเศษส่วน H-carpet ( 97 ไบต์ ):

for(;$i<$n=3**$argn;$i+=print"$s\n")for($s=H,$e=1;$e<$n;$e*=3)$s.=str_pad($i/$e%3&1?$s:'',$e).$s;

สิ่งนี้สามารถปรับรูปแบบได้ด้วยวิธีต่อไปนี้:

for(;($i+=$e&&print"$s\n")<$n=3**$argn;)for($s=H,$e=1;$e<$n;$e*=3)$s.=str_pad($i/$e%3&1?$s:'',$e).$s;

$e&&printป้องกันทวนแรกและยังไม่ได้เพิ่มขึ้นprint$i

และในที่สุด ( 93 ไบต์ ):

for(;$H>$e*=3or$e=($i+=$e&&print"$s\n")<${$s=H}=3**$argn;)$s.=str_pad($i/$e%3&1?$s:'',$e).$s;

$H>$e*=3 จะล้มเหลวในครั้งแรกเนื่องจากตัวแปรทั้งสองไม่ได้กำหนดไว้


1

การลบอักขระในสตริง

join(explode(" ",$string));

บันทึก 1 อักขระเปรียบเทียบกับ

str_replace(" ","",$string);

โปรดทราบว่าวิธีนี้ใช้ได้กับสตริงทั้งหมด (ไม่ใช่ข้อยกเว้น) ไม่ใช่เฉพาะอักขระ
— CalculatorFeline

@CalculatorFeline เหตุใดจึงไม่ควรใช้กับสตริงว่าง มันไม่สมเหตุสมผลหรือในกรณีนี้
— JörgHülsermann

เวอร์ชันแรกไม่สามารถใช้งานได้""และมันก็ไม่มีประโยชน์อะไรเลย
— CalculatorFeline

1
@CalculatorFeline และสำหรับกรณีนี้การแก้ปัญหาศูนย์ไบต์จะดีกว่ามาก มันไม่มีเหตุผลที่จะทำอย่างนี้
— JörgHülsermann

3
)ตัวอย่างเช่นการเข้าร่วมของคุณจะหายไป และstrtr($string,[" "=>""])ยิ่งสั้น
— ติตัส


1

ใช้โอเปอเรเตอร์บูลีนแทนstrtoupper()และstrtolower()

หากคุณทำงานเฉพาะกับสตริงที่ประกอบด้วยอักขระตัวอักษรคุณสามารถใช้ตัวดำเนินการบูลีนเพื่อเปลี่ยนเป็นตัวพิมพ์ใหญ่หรือตัวพิมพ์เล็กโดยมีการกดแป้นน้อยกว่าฟังก์ชันในตัวของ PHP

ตัวอย่าง:

// Convert lowercase to uppercase
$s = "g";
echo strtoupper($s);  // Outputs 'G', uses 20 characters
echo~" "&$s;          // Outputs 'G', uses 12 characters

// Convert uppercase to lowercase
$s = "G";
echo strtolower($s);  // Outputs 'g', uses 20 characters
echo$s^" ";           // Outputs 'g', uses 11 characters

// Switch case of each character
$s = "Gg";
echo$s^"  ";          // Outputs 'gG', uses 12 characters

สิ่งต่าง ๆ มีความซับซ้อนน้อยกว่าสำหรับสายอักขระที่มีความยาวตามอำเภอใจ แต่ตัวดำเนินการ&และ^จะตัดทอนผลลัพธ์เป็นความยาวของสตริงอินพุตที่สั้นกว่า ตัวอย่างเช่นถ้า$Wเป็นสตริงของช่องว่างอย่างน้อยตราบใดที่อินพุตใด ๆ$sก็~$W&$sจะเท่ากับstrtoupper($s)และ$s|$W^$sเท่ากับstrtolower($s)( $s|$Wโดยตัวมันเองจะสร้างสตริงที่มีช่องว่างเพิ่มเติมเว้นแต่$sและ$Wมีความยาวเท่ากัน)


0

ใช้ฟังก์ชั่เลิก
หากคุณสามารถใช้ POSIX แทน PERL regex โดยไม่ต้องเสียมากกว่า 5 ไบต์ในการแสดงออกการใช้งานeregหรือeregiแทนpreg_match, splitหรือsplitiแทน preg_split
splitนอกจากนี้ยังสามารถใช้เป็นคำเหมือนสำหรับexplodeตัวคั่นส่วนใหญ่

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


2
ระวัง! สิ่งเหล่านี้ถูกลบใน PHP 7.0
— ร่ม
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.