การแปลงสตริงจาก snake_case เป็น CamelCase ใน Ruby


171

ฉันพยายามแปลงชื่อจากเคสงูเป็นเคสอูฐ มีวิธีการในตัวหรือไม่?

เช่น: "app_user"ถึง"AppUser"

(ฉันมีสตริง"app_user"ฉันต้องการแปลงให้เป็นรุ่นAppUser)

คำตอบ:


251

หากคุณใช้ Rails String # camelizeคือสิ่งที่คุณกำลังมองหา

  "active_record".camelize                # => "ActiveRecord"
  "active_record".camelize(:lower)        # => "activeRecord"

หากคุณต้องการได้คลาสจริงคุณควรใช้String # constantizeด้านบน

"app_user".camelize.constantize

44
คุณควรเพิ่มว่านี่เป็น Rails นอกเหนือจาก String มันไม่ได้ทำงานกับทับทิมบริสุทธิ์
iGEL

2
มันติดแท็กruby-on-railsดังนั้นฉันเดาว่ามันไม่ใช่ปัญหา แต่ขอบคุณที่พูดถึง
Sergio Tulentsev

6
คุณไม่จำเป็นต้อง camelize ก่อนทำการลดขนาด ใช้#classifyแทน "some_namespace/module/class_name".classify => "SomeNamespace::Module::ClassName"
Chris Heald

5
@chris #classify: ไม่เหมือนกัน #classify ส่งคืนสตริงในขณะที่ #constantize ค้นหาค่าคงที่ในบริบท (และไม่จำเป็นต้องมี camelize) 'active_record'.constantize ให้ข้อผิดพลาด' active_record'.camelize.constantize ส่งคืนค่าคงที่ ActiveRecord, 'active_record'.classify ส่งคืนสตริง' ActiveRecord ' และถ้าคุณทำ 'no_class'.camelize.constantize คุณจะได้รับข้อผิดพลาด (ไม่มี NoClass คงที่) แต่' no_class'.classify จะส่งกลับสตริง 'NoClass' อย่างมีความสุข
Kanat Bolazar

ในการใช้วิธีการเหล่านี้ของ Rails จาก Ruby บริสุทธิ์require "active_support/core_ext/string"นั้นเพียงพอแล้วหากมี Rails ติดตั้งอยู่แล้ว
Masa Sakano

120

แล้วอันนี้ละ?

"hello_world".split('_').collect(&:capitalize).join #=> "HelloWorld"

พบได้ในความคิดเห็นที่นี่: จัดประเภทสตริง Ruby

ดูความคิดเห็นโดยWayne Conrad


10
คุณยอดเยี่ยมขอบคุณ ฉันไม่ต้องการที่จะรวมห้องสมุดรถไฟเพียงเพื่องานเล็ก ๆ นี้ นี่คือสิ่งที่สวยงาม :)
Gerry

11
นี่เป็นหนึ่งในคำตอบที่แท้จริงเพียงคำถามเดียว ไม่ได้ใช้ไลบรารี Rails
Luis Ortega Araneda

40

classifyถ้าคุณใช้ทางรถไฟใช้ มันจัดการกรณีขอบได้ดี

"app_user".classify # => AppUser
"user_links".classify   # => UserLink

บันทึก:

คำตอบนี้เฉพาะเจาะจงกับคำอธิบายที่ให้ไว้ในคำถาม (ไม่เฉพาะเจาะจงกับชื่อคำถาม) หากพยายามแปลงสตริงเป็นอูฐก็ควรใช้คำตอบของSergio ผู้ถามระบุว่าเขาต้องการแปลงapp_userเป็นAppUser(ไม่ใช่App_user) ดังนั้นคำตอบนี้ ..


4
สำหรับสภาพแวดล้อมของ Rails นี้สมบูรณ์แบบ
gayay

โปรดทราบว่าclassifyส่งคืนสตริงคุณต้องโทรconstantizeหลังจากนั้นเพื่อแปลงเป็นคลาสจริง
สเตฟาน

1
ข้อแม้ที่สำคัญclassifyคือสตริงพหูพจน์จะกลายเป็นเอกพจน์ ... 'age_in_years'.classifyกลายเป็นAgeInYear
3

@ br3nt มันไม่ได้ทำให้มีหลายรูปแบบตั้งแต่ activerecord4.2.11
Ulysse BN

23

ที่มา: http://rubydoc.info/gems/extlib/0.9.15/String#camel_case-instance_method

เพื่อการเรียนรู้:

class String
  def camel_case
    return self if self !~ /_/ && self =~ /[A-Z]+.*/
    split('_').map{|e| e.capitalize}.join
  end
end

"foo_bar".camel_case          #=> "FooBar"

และสำหรับตัวแปร LowerCase:

class String
  def camel_case_lower
    self.split('_').inject([]){ |buffer,e| buffer.push(buffer.empty? ? e : e.capitalize) }.join
  end
end

"foo_bar".camel_case_lower          #=> "fooBar"

6
@pguardiario หากวงล้อเรียกว่าActiveSupportโปรดสร้างมันใหม่
shime

ฉันคิดว่าตัวแปรลดลงเป็นสิ่งที่ผิด บล็อกการฉีดไม่ควรปรับเปลี่ยนบัฟเฟอร์โดยตรง แต่คืนค่าใหม่ให้กับบัฟเฟอร์:self.split('_').inject([]){ |buffer,e| buffer + [buffer.empty? ? e : e.capitalize] }.join
Sven Koschnicke

19

เกณฑ์มาตรฐานสำหรับโซลูชันทับทิมบริสุทธิ์

ฉันใช้ความเป็นไปได้ทุกอย่างที่ฉันมีในใจที่จะทำด้วยรหัสทับทิมบริสุทธิ์นี่คือ:

  • ใช้ประโยชน์และ gsub

    'app_user'.capitalize.gsub(/_(\w)/){$1.upcase}
  • แยกและแผนที่โดยใช้&ชวเลข (ขอบคุณคำตอบของผู้ใช้ 3869936)

    'app_user'.split('_').map(&:capitalize).join
  • แยกและแผนที่ (ขอบคุณคำตอบของ Mr. Black)

    'app_user'.split('_').map{|e| e.capitalize}.join

และนี่คือเกณฑ์มาตรฐานสำหรับสิ่งเหล่านี้เราจะเห็นได้ว่า gsub นั้นค่อนข้างแย่สำหรับเรื่องนี้ ฉันใช้ 126 080 คำ

                              user     system      total        real
capitalize and gsub  :      0.360000   0.000000   0.360000 (  0.357472)
split and map, with &:      0.190000   0.000000   0.190000 (  0.189493)
split and map        :      0.170000   0.000000   0.170000 (  0.171859)

11

ฉันมาที่นี่เพื่อค้นหาสิ่งที่ตรงกันข้ามกับคำถามของคุณเริ่มจากอูฐเคสไปจนถึงเคสงู ใช้ขีดเส้นใต้สำหรับสิ่งนั้น (ไม่ใช่ decamelize):

AppUser.name.underscore # => "app_user"

หรือถ้าคุณมีสตริงตัวอูฐอยู่แล้ว:

"AppUser".underscore # => "app_user"

หรือถ้าคุณต้องการได้รับชื่อตารางซึ่งอาจเป็นสาเหตุที่คุณต้องการกรณีงู:

AppUser.name.tableize # => "app_users"


ทำไมไม่ใช้AppUser.table_name? คุณจะต้องแน่ใจว่ามีชื่อตารางจริงหากไม่ใช่ app_users แต่มีบางอย่างที่กำหนดไว้ที่อื่น
Ulysse BN

3

ฉันรู้สึกอึดอัดเล็กน้อยที่จะเพิ่มคำตอบเพิ่มเติมที่นี่ ตัดสินใจที่จะใช้วิธีการทับทิมบริสุทธิ์ที่อ่านง่ายและน้อยที่สุดโดยไม่คำนึงถึงมาตรฐานที่ดีจาก @ ulysse-bn ในขณะที่:classโหมดเป็นสำเนาของ @ user3869936 :methodโหมดที่ฉันไม่เห็นในคำตอบอื่น ๆ ที่นี่

  def snake_to_camel_case(str, mode: :class)
    case mode
    when :class
      str.split('_').map(&:capitalize).join
    when :method
      str.split('_').inject { |m, p| m + p.capitalize }
    else
      raise "unknown mode #{mode.inspect}"
    end
  end

ผลลัพธ์คือ:

[28] pry(main)> snake_to_camel_case("asd_dsa_fds", mode: :class)
=> "AsdDsaFds"
[29] pry(main)> snake_to_camel_case("asd_dsa_fds", mode: :method)
=> "asdDsaFds"

1
กรณีของอูฐอยู่ในความเป็นจริงก่อนลดลง มิฉะนั้นจะมีชื่อว่า PascalCase (หรือบางครั้งเป็นตัวอูฐด้านบน) แม้ว่าในคำถามนี้มันคลุมเครือ!
Ulysse BN

2
@ UlysseBN, tbh ฉันไม่ได้เข้าสู่ประวัติศาสตร์ของคำ การเรียกร้องของวิกิพีเดียเป็นส่วนหนึ่งของPascalCase CamelCaseนี่คือสิ่งที่ฉันรู้ - กรณีอูฐนั้นใช้ได้กับทั้งสองอย่าง แต่ฉันไม่เคยตรวจสอบ ขอบคุณที่พูดถึง PascalCase en.wikipedia.org/wiki/Camel_case
akostadinov

2
นี่คือคำตอบที่ดีที่สุดในหน้า imo มันจะดีถ้า:methodรุ่นได้downcaseเป็นครั้งแรกเพื่อที่จะสามารถนำมาใช้ทั้งในและlower_snake_case UPPER_SNAKE_CASE
skagedal

0

วิธีอื่น ๆ ส่วนใหญ่ที่ระบุไว้ที่นี่เป็นวิธีเฉพาะของ Rails หากคุณต้องการทำสิ่งนี้ด้วย Ruby บริสุทธิ์ต่อไปนี้เป็นวิธีที่กระชับที่สุดที่ฉันคิดขึ้นมาด้วย (ขอบคุณ @ ulysse-bn สำหรับการปรับปรุงที่แนะนำ)

x="this_should_be_camel_case"
x.gsub(/(?:_|^)(\w)/){$1.upcase}
    #=> "ThisShouldBeCamelCase"

คำจำกัดความของ "อูฐกรณี" ของคุณมี จำกัด เกินไป ตัวอย่างเช่นชื่อคลาสใน Java และ Ruby เป็นกรณีอูฐ MyFavoriteClass ... แต่พวกเขายังไม่มีตัวอักษรเริ่มต้นที่ต่ำกว่า บางครั้งกรณีของอูฐมีตัวพิมพ์ใหญ่เริ่มต้น บางครั้งมันก็ไม่ได้
masukomi

ใช้ 2 Regex ที่คุณสามารถใช้ได้เพียงอันเดียวคือ overkill คุณสามารถใช้เฉพาะกลุ่มที่ไม่ได้ดักจับ:x.gsub(/(?:_|^)(\w)/){$1.upcase}
Ulysse BN

@ UlysseBN และเรากลับไปที่gsubโซลูชันของคุณดูเหมือนว่าจะช้ากว่าเมื่อเทียบกับmapโซลูชัน
akostadinov

0

ขยายสตริงเพื่อเพิ่ม Camelize

ใน Ruby บริสุทธิ์คุณสามารถขยายคลาสสตริงโดยใช้โค้ดเดียวกันจาก Rails .camelize

class String
  def camelize(uppercase_first_letter = true)
    string = self
    if uppercase_first_letter
      string = string.sub(/^[a-z\d]*/) { |match| match.capitalize }
    else
      string = string.sub(/^(?:(?=\b|[A-Z_])|\w)/) { |match| match.downcase }
    end
    string.gsub(/(?:_|(\/))([a-z\d]*)/) { "#{$1}#{$2.capitalize}" }.gsub("/", "::")
  end
end
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.