การจัดรูปแบบสตริงสไตล์ printf


9

ท้าทาย

เขียนฟังก์ชั่นที่ใช้การprintfจัดรูปแบบสตริงC- style

กฎระเบียบ

  1. คุณจะต้องดำเนินการอย่างน้อย%%, %c, %s, และ%d%f
  2. คุณต้องไม่ใช้วิธีการจัดรูปแบบสตริงในตัว
  3. คุณต้องไม่เรียกใช้โปรแกรมภายนอกหรือเชื่อมต่ออินเทอร์เน็ตจากโปรแกรมของคุณ
  4. มันขึ้นอยู่กับคุณที่จะตัดสินใจว่าจะจัดการกับอินพุตที่ไม่ถูกต้อง แต่โปรแกรมของคุณจะต้องไม่หยุดอย่างผิดปกติ
  5. คุณควรเขียนฟังก์ชัน Variadicถ้าเป็นไปได้

คำสำคัญ "ต้อง", "ไม่ต้อง", "จำเป็นต้องใช้", "ไม่ควร", "ไม่ควร", "ไม่ควร", "ไม่ควร", "แนะนำ", "อาจ" และ "ตัวเลือก" ในเอกสารนี้ จะตีความตามที่อธิบายในRFC 2119


อะไร%cทำอย่างไร มั่นใจว่าสวย%s, %dและ%fมีการสตริง ints และลอย respectivelly %cแต่ไม่แน่ใจเกี่ยวกับ
Sumurai8

%cแสดงค่า ASCII ของ Int ผ่าน IIRC
marinus

มันพิมพ์ตัวละครดังนั้น97และ'a'ทั้งคู่ก็จะกลายเป็นaเอาท์พุท
nyuszika7h

ไม่จำเป็นต้องสนับสนุนรูปแบบบางอย่าง%-02dใช่มั้ย แค่นั้นสาม% c,% s,% d?
คุณ

@YOU ถูกต้อง เพียงพอ.
nyuszika7h

คำตอบ:


4

APL (73)

{⊃,/,⌿↑(⊂2∘↓¨Z⊂G),⊂{'c'0≡⍵,∊⊃⍺:⎕UCS⍺⋄⍕⍺}/⍵,⍪⌷∘G¨1↓1+(Z←G='%')/⍳⍴G←'%!',⍺}

การทดสอบบางอย่าง:

      'a:%c b:%s c:%d'{⊃,/,⌿↑(⊂2∘↓¨Z⊂G),⊂{'c'0≡⍵,∊⊃⍺:⎕UCS⍺⋄⍕⍺}/⍵,⍪⌷∘G¨1↓1+(Z←G='%')/⍳⍴G←'%!',⍺} 65 'foo' 67
a:A b:foo c:67 

      printf←{⊃,/,⌿↑(⊂2∘↓¨Z⊂G),⊂{'c'0≡⍵,∊⊃⍺:⎕UCS⍺⋄⍕⍺}/⍵,⍪⌷∘G¨1↓1+(Z←G='%')/⍳⍴G←'%!',⍺}
      '1:%s 2:%s 3:%d 4:%c 5:%c' printf 'foo' 'bar' 100 110 'z'
1:foo 2:bar 3:100 4:n 5:z   
      'The %s brown %c%c%c jumps over the %s dog.' printf 'quick' 102 111 'x' 'lazy'
The quick brown fox jumps over the lazy dog.

คำอธิบาย:

  • G←'%!',⍺: คำนำหน้าตัวระบุตัวแทนเชิดไปยังสตริง
  • (Z←G='%')/⍳⍴G: ค้นหาดัชนีของ%ตัวละครทั้งหมดในสตริง; เก็บ bitmask ด้วยZ
  • ⌷∘G¨1↓1+: เลือกอักขระทั้งหมดที่อยู่ถัดจาก%s และปล่อยดัมมี่
  • ⍵,⍪: จับคู่ตัวระบุแต่ละตัวกับค่าของมันจากอาร์กิวเมนต์ที่ถูกต้อง
  • {... }/: เรียกใช้ฟังก์ชันต่อไปนี้ในแต่ละคู่:
    • 'c'0≡⍵,∊⊃⍺: ถ้าอาร์กิวเมนต์เป็นตัวเลขและตัวระบุคือc:
    • :⎕UCS⍺: จากนั้นคืนค่า Unicode ของอาร์กิวเมนต์
    • ⋄⍕⍺: มิฉะนั้นส่งคืนการแทนค่าสตริงของอาร์กิวเมนต์
  • : ล้อมรอบ
  • ⊂2∘↓¨Z⊂G: แยกสตริงบน%s จากนั้นลบอักขระสองตัวแรกของแต่ละสตริงย่อย (นี่คือตำแหน่งที่จำลองมา) และใส่ผลลัพธ์ของสิ่งนั้น
  • : สร้างเมทริกซ์จากสองอาร์เรย์ที่ล้อมรอบจับคู่แต่ละสตริงย่อยกับค่าที่ควรปฏิบัติตาม
  • ,⌿: เข้าร่วมแต่ละสตริงย่อยด้วยค่า
  • ⊃,/: จากนั้นเข้าร่วมสตริงที่เกิด

มันสนุกเสมอที่ได้เห็นภาษาลึกลับที่ดูเหมือนพูดไม่ชัด ;)
nyuszika7h

2
@ nyuszika7h: จริง ๆ แล้วนี่เป็นภาษาที่จริงจัง มันมาจากปี 1960 และยังคงใช้งานอยู่ มันจะดูน้อยกว่าที่พูดพล่อยๆถ้ามันไม่ได้เล่นกอล์ฟ
marinus

ฉันเห็นน่าสนใจ
nyuszika7h

@ nyuszika7h: ในทางเทคนิคแล้วมันเป็นภาษาโปรแกรมเชิงลิสต์ดังนั้นคุณอาจพูดได้ว่ามันออกแบบมาสำหรับโค้ดกอล์ฟโดยเฉพาะการพิจารณาว่ามันใช้ชุดอักขระพิเศษที่ตั้งใจจะทำให้โปรแกรมอ่านได้ง่ายขึ้นและ verbose น้อยลง และมันเป็นแรงบันดาลใจสำหรับภาษาโปรแกรม Jและ GolfScript
Konrad Borowski

@ xfix ฉันคิดว่า LISP เป็นรายการภาษาโปรแกรมเชิง? เราใช้ APL ในมหาวิทยาลัยเพื่อทำงานจริง - ความสามารถในการจัดการอาร์เรย์นั้นมีประโยชน์จริง ๆ J ได้รับการออกแบบโดยหนึ่งในนักประดิษฐ์ของ APL ในฐานะ "ตัวตายตัวแทน" - แน่นอนว่าไม่ได้หมายความว่ามันจะไม่เป็นประโยชน์สำหรับโค้ดกอล์ฟ ...
Jerry Jeremiah

2

Ruby: 102 ตัวอักษร

f=->s,*a{s.gsub(/%(.)/){$1==?%??%:a.shift.send({?c=>:chr,?s=>:to_s,?d=>:to_i,?f=>:to_f}[$1])rescue$&}}

วิ่งตัวอย่าง:

irb(main):001:0> f=->s,*a{s.gsub(/%(.)/){$1==?%??%:a.shift.send({?c=>:chr,?s=>:to_s,?d=>:to_i,?f=>:to_f}[$1])rescue$&}}
=> #<Proc:0x96634ac@(irb):1 (lambda)>

irb(main):002:0> puts f["percent : %%\n   char : %c or %c\n string : %s or %s or %s\ndecimal : %d or %d or %d\n  float : %f or %f or %f\ninvalid : %x or %s or %d or %f", 65, 'B', 'format me', 42, Math::PI, 42, Math::PI, '2014', 42, Math::PI, '2014', 'more']
percent : %
   char : A or B
 string : format me or 42 or 3.141592653589793
decimal : 42 or 3 or 2014
  float : 42.0 or 3.141592653589793 or 2014.0
invalid : %x or  or 0 or 0.0
=> nil

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


คุณสามารถจัดหาฟังก์ชั่นที่ไม่ระบุชื่อดังนั้นปล่อยผู้นำf
cat

จริง แต่อย่างที่ฉันจำได้ตอนที่โพสต์สิ่งนี้ฟังก์ชั่นนิรนามไม่ได้รับการยอมรับอย่างเป็นเอกฉันท์ สำหรับตอนนี้คำตอบ Lua ก็ไม่ได้รับการอัพเดตเป็นฟังก์ชั่นนิรนาม (เพื่อประหยัดจำนวนตัวอักษร) ฉันคิดว่าฉันจะไม่เริ่มการอัพเดท
จัดการ

2

Lua 5.2, 115 ไบต์

-- Function definition, 115 chars
function f(f,...)n,t=0,{...}return(f:gsub('%%(%a)',function(s)n=n+1return(({c=s.char})[s]or tostring)(t[n])end))end

-- Usage example
print(f('Happy %cew %d %s %f',78,2014,'Year!',math.pi))
-- Output: Happy New 2014 Year! 3.1415926535898

ทำได้ดีนี่. Lua รุ่นใด 5.1.5 ให้ "ตัวเลขที่มีรูปแบบไม่ถูกต้องใกล้กับ" 1return "" ปัญหาเล็ก ๆ เกี่ยวกับ“% c” มันล้มเหลวใน 'N' แทนที่จะเป็น 78 หรือมันเป็นเพียงลักษณะเฉพาะของ Lua เก่าของฉันหรือไม่
จัดการ

@manatwork - ลองที่นี่
Egor Skriptunoff

Yepp ทำงานที่นั่น
จัดการ

ได้ผลสำหรับฉันใน Lua 5.2.3
nyuszika7h

1

C ++ (281 ตัวอักษร)

#include<sstream>
#include<cstdarg>
#define q(x)va_arg(v,x);break;case
std::string p(char*f,...){std::ostringstream r;va_list v;va_start(v,f);while(*f)if(*f=='%')switch(++f,*f++){case's':r<<q(char*)'d':r<<q(int)'c':r<<(char)q(int)'%':r<<'%';}else r<<*f++;va_end(v);return r.str();}

ฉันเกลียด C ++ แต่ดูเหมือนจะเป็นทางเลือกที่ดี (ฉันจะไปกับ C จริงๆหากไม่ใช่char*ตัวชี้นั้นต้องใช้ความพยายามมากเกินไปที่จะเป็นประโยชน์จริง ๆ ) รับchar*ข้อโต้แย้งและstd::stringผลลัพธ์ แต่เฮ้นั่นคือ C ++ ดังนั้นใครสนใจเรื่องความมั่นคง (ในภาษาที่ตัวเองไม่สอดคล้องกัน)?


สิ่งนี้ไม่ได้รวบรวมเพราะมันไม่มีฟังก์ชั่นหลัก
nyuszika7h

@ nyuszika7h: mainคำถามที่ได้รับเกี่ยวกับการทำฟังก์ชั่นไม่ได้ แต่ถ้าคุณต้องการตัวอย่างmainลองgist.github.com/xfix/8238576 (ฉันใช้อันนั้นขณะทดสอบฟังก์ชั่นนี้)
Konrad Borowski

จริงคุณไม่สามารถสร้างmainฟังก์ชั่นที่มีความหมายได้การเพิ่มเพียงแค่เพิ่มจำนวนตัวละคร หากฉันไม่ต้องการแก้ไขรหัสฉันสามารถเพิ่มไฟล์ส่วนหัวและ#includeจากโปรแกรมทดสอบของฉัน
nyuszika7h

1

Java , 201 186 174 ไบต์

12 ไบต์ขอบคุณ Kevin Cruijssen

String f(String s,Object...a){String r="";for(char c,i=0,j=0;i<s.length();r+=c==37?(c=s.charAt(i++))<38?c:c==99?(char)(int)a[j++]:a[j++]:c==37?"":c)c=s.charAt(i++);return r;}

ลองออนไลน์!


ผมไม่แน่ใจว่าทั้งหมด แต่ผมคิดว่าคุณสามารถลบจาก=s.charAt(0) มันยังใช้งานได้ใน TIO เมื่อฉันทำเช่นนั้น char c=s.charAt(0)
Kevin Cruijssen

@KevinCruijssen ฉันสาบานว่ามันค่อนข้างฉลาด
Leun Nun

ฉันรู้ว่าไม่นานมานี้ แต่คุณสามารถบันทึก 8 ไบต์ได้มากขึ้นโดยการพิมพ์โดยตรง: void f(String s,Object...a){for(char c,i=0,j=0;i<s.length();System.out.print(c==37?(c=s.charAt(i++))<38?c:c==99?(char)(int)a[j++]:a[j++]:c==37?"":c))c=s.charAt(i++);} 166 ไบต์ (และอีกบางส่วนโดยแปลงเป็น Java 8 แต่นั่นไม่ใช่สิ่งที่คุณต้องการจริง ๆ หรือ?)
Kevin Cruijssen
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.