Ruby :: Substituting variables into an existing string

Posted by PunNeng, Thu Jan 25 11:23:00 UTC 2007

ถ้าเราต้องการจะสร้าง string โดยที่ต้องการใส่ตัวแปรลงไปด้วยในก้อน string น้ันๆ อาจจะทำได้จากการใช้ #{} แทรกเข้าไปใน string เช่น

"#{my_variable}"

ถ้าต้องการเปลี่ยน ก็เพียงแค่เปลี่ยนค่า my_variable เช่น my_variable = "new string or expression" หรือว่า my_variable = any_variable จริงๆ แล้ว เราไม่ต้องมาทำการเซ็ตค่าให้ my_variable ตลอด ใน ruby มี 2 วิธี ที่คอยจัดการให้ของพวกนี้ง่ายขึ้่น คือ แบบ printf และ ERB template มาดูทางด้าน printf ตามแนวของ C หรือ python ก่อน

template = 'Oceania has always been at war with %s.%'
template % 'Eurasia'  # => "Oceania has always been at war with Eurasia."
template % 'Eastasia' # => "Oceania has always been at war with Eastasia."

'To 2 decimal places: %.2f' % Math::PI     # => "To 2 decimal places: 3.14"
'Zero-padded: %.5d' % Math::PI             # => "Zero-padded: 00003"

มาดูทางด้าน ERB บ้าง
มันก็มีลักษณะคล้ายๆ กับ php หรือ jsp นั่นแหละ เพียงแต่เปลี่ยนเป็น code ของ ruby เท่านั้น เช่น php จะใช้ <?php //php code ?> ฝั่ง ruby จะเป็น <% #ruby code %> ซึ่งมันอาจจะเป็น expression หรือ ตัวแปร ก็ได้ มาดูตัวอย่าง

require 'erb'

template = ERB.new %q{Chunky <= food %>!}
food = "bacon"
template.result(binding)                   # => "Chunky bacon!"
food = "peanut butter"
template.result(binding)                   # = > "Chunky peanut butter!"

ตัว %q{} ทำหน้าที่สร้าง single quote string เราสามารถใช้ %Q{} ในการสร้าง double quote string ด้วยเช่นกัน ถ้าเราไม่ได้รันอยู่บน irb เราสามารถใช้ template.result ได้เลย ข้ามการเรียก Kernel#binding ไปได้เลย
ตัว .rhtml ของ rails ก็ใช้ตัว ERB นี่แหละครับ ในการแสดงผล นอกจากตัวอย่างข้างต้น ใน ERB ยังสามารถใช้ loops หรือ conditions ได้อีกด้วย ลักษณะเหมือน serverside script ทั่วๆ ไป โดยมีข้อสังเกตนิดนึงคือ <% %> ไว้สำหรับ expression หรือ loop หรือ conditions ต่างๆ นานา มันจะไม่แสดง(print) ออกมา แต่ถ้าเราใช้ <%= %> มันจะเป็นการแสดงสิ่งที่อยู่ข้างในออกมา ยังมีทางเลือกอื่นอืีกครับ จากอันนี้ เรารู้ว่าถ้าใช้ single quote เจ้าตัว #{} มันจะใช้ไ่ม่ได้ เราสามารถใช้ eval ช่วยได้

class String
  def substitute(binding=TOPLEVEL_BINDING)
    eval(%{"#{self}"}, binding)
    # %{} <=> here string
  end
end

template = %q{Chunky %{food}!}                # => "Chunky \#{food}!"
# %q{} <=> single quote
food = 'bacon'
template.substitue(binding)                   # => "Chunky bacon!"
food = 'peanut butter'
template.substitue(binding)                   # => "Chunky peanut butter!"

การใช้ eval นี้ต้องระวังหน่อย เราอาจจะเจอการฉีด(injection) อะไรบางอย่างเข้ามาใจ code ของเราโดยตรง อาจจะเป็นช่องว่างในการเปิดให้ชาวบ้านมาโจมตีได้ เช่น อาจจะโดนฉีด command มา มันก็จะทำการรัน command นั้นๆ เช่น

eval("system('ls')",binding)

ถ้าอยู่ในรูปแบบนี้ละก็ เสร็จแน่ ตัว system มันเป็น method นึงของคลาส kernel มันจะทำการรันคำสั่ง ls ตามที่เราใส่เข้าไป งืมๆๆ แต่ตัวอย่างที่่ให้มา ถูกจัดการเรียบร้อยแล้ว ด้วยการห่อด้วย single quote อีกทีนึง ตอนที่เราสั่ง food = '#{system("ls")}' มันจะมองให้ถูกเป็นแค่ string เท่านั้น ถ้าเปลี่ยนเป็น double quote ละก็ เป็นเรื่อง ลองดูคำสั่งนี้

template = %q{#{food}!}
food = '#{system("ls")}'
puts template.substitute(binding)
# Chunky #{system("ls")}!

มันจะถูกมองเป็น string เท่านั้น ลองเปลี่ยนเป็น food = "#{system("ls")}" นะครับ

แก้ไขล่าสุด วันที่ 24 กรกฏาคม 2550 เวลา 22.49 น.

Filed Under: Ruby | Tags: howto ruby string

Comments

Have your say

A name is required. You may use HTML in your comments.




codegent: we're hiring