Konvertieren eines Strings von snake_case in CamelCase in Ruby


171

Ich versuche, einen Namen vom Schlangenfall in den Kamelfall umzuwandeln. Gibt es eingebaute Methoden?

ZB: "app_user"zu"AppUser"

(Ich habe eine Zeichenfolge, die "app_user"ich in ein Modell konvertieren möchte AppUser).

Antworten:


251

Wenn Sie Rails verwenden, ist String # camelize genau das, wonach Sie suchen.

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

Wenn Sie eine tatsächliche Klasse erhalten möchten, sollten Sie darüber hinaus String # constize verwenden .

"app_user".camelize.constantize

44
Sie sollten hinzufügen, dass dies eine Rails-Ergänzung zu String ist, die mit reinem Ruby nicht funktioniert.
iGEL

2
Es ist markiert ruby-on-rails, also ist es wohl kein Problem. Aber danke fürs Erwähnen.
Sergio Tulentsev

6
Sie müssen vor dem Konstantisieren nicht kamelisieren. Verwenden Sie #classifystattdessen. "some_namespace/module/class_name".classify => "SomeNamespace::Module::ClassName"
Chris Heald

5
@chris #classify: Nicht dasselbe. #classify gibt einen String zurück, während #constantize im Kontext konstant nachschlägt (und camelize benötigt). 'active_record'.constantize gibt einen Fehler aus,' active_record'.camelize.constantize gibt die Konstante ActiveRecord zurück, 'active_record'.classify gibt die Zeichenfolge' ActiveRecord 'zurück. Und wenn Sie 'no_class'.camelize.constantize gemacht haben, erhalten Sie einen Fehler (keine solche Konstante NoClass), aber' no_class'.classify gibt glücklich den 'NoClass'-String zurück.
Kanat Bolazar

Um diese Methoden von Rails aus reinem Ruby nutzen zu können, require "active_support/core_ext/string"ist ausreichend, sofern Rails bereits installiert ist.
Masa Sakano

120

Wie wäre es mit diesem?

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

In den Kommentaren hier zu finden: Klassifizieren Sie eine Ruby-Zeichenfolge

Siehe Kommentar von Wayne Conrad


10
Du bist großartig, danke. Ich wollte keine Rails-Bibliotheken nur für eine so kleine Aufgabe einbinden müssen. Das ist schön. :)
Gerry

11
Dies ist eine der wenigen wirklichen Antworten auf die Frage. Keine Rails-Bibliotheken verwenden.
Luis Ortega Araneda

40

Wenn Sie Rails verwenden, verwenden Sie classify. Es handhabt Randfälle gut.

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

Hinweis:

Diese Antwort ist spezifisch für die Beschreibung in der Frage (sie ist nicht spezifisch für den Fragentitel). Wenn man versucht, einen String in einen Kamelkasten umzuwandeln, sollte man Sergios Antwort verwenden. Der Fragesteller gibt an, dass er app_userzu AppUser(nicht App_user) konvertieren möchte , daher diese Antwort.


4
Für Rails-Umgebungen ist dies perfekt.
Ghayes

Beachten Sie, dass classifyeine Zeichenfolge zurückgegeben wird, die Sie anschließend aufrufen müssen constantize, um sie in eine tatsächliche Klasse zu konvertieren.
Stefan

1
Eine wichtige Einschränkung classifyist, dass pluralisierte Saiten singulär werden ... 'age_in_years'.classifywerdenAgeInYear
br3nt

@ br3nt es pluralisiert nicht seit activerecord4.2.11
Ulysse BN

23

Quelle: http://rubydoc.info/gems/extlib/0.9.15/String#camel_case-instance_method

Zu Lernzwecken:

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"

Und für die LowerCase-Variante:

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 Wenn das Rad ActiveSupport heißt , erfinden Sie es bitte neu.
Shime

Ich denke, die LowerCase-Variante ist falsch. Der Inject-Block sollte den Puffer nicht direkt manipulieren, sondern den neuen Wert für den Puffer zurückgeben:self.split('_').inject([]){ |buffer,e| buffer + [buffer.empty? ? e : e.capitalize] }.join
Sven Koschnicke

19

Benchmark für reine Ruby-Lösungen

Ich habe alle Möglichkeiten genutzt, um dies mit reinem Ruby-Code zu tun. Hier sind sie:

  • kapitalisieren und gsub

    'app_user'.capitalize.gsub(/_(\w)/){$1.upcase}
  • &Teilen und Zuordnen mit Kurzschrift (dank der Antwort von user3869936)

    'app_user'.split('_').map(&:capitalize).join
  • Split und Map (dank Mr. Blacks Antwort)

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

Und hier ist der Benchmark für all dies. Wir können sehen, dass gsub dafür ziemlich schlecht ist. Ich habe 126 080 Wörter verwendet.

                              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

Ich bin hierher gekommen, um die Umkehrung Ihrer Frage zu suchen, von Kamelfall zu Schlangenfall. Verwenden Sie dazu einen Unterstrich (nicht dekamellisieren):

AppUser.name.underscore # => "app_user"

oder, wenn Sie bereits eine Kamelfallschnur haben:

"AppUser".underscore # => "app_user"

oder, wenn Sie den Tabellennamen erhalten möchten, weshalb Sie wahrscheinlich den Schlangenfall möchten:

AppUser.name.tableize # => "app_users"


Warum nicht benutzen AppUser.table_name? Sie werden auch sicherstellen, dass der wahre Tabellenname vorhanden ist, wenn es sich nicht um app_users handelt, sondern um etwas, das an anderer Stelle definiert ist.
Ulysse BN

3

Es ist mir etwas unangenehm, hier weitere Antworten hinzuzufügen. Beschlossen, den lesbarsten und minimalsten reinen Rubin-Ansatz zu wählen, ohne den netten Benchmark von @ ulysse-bn zu berücksichtigen. Während der :classModus eine Kopie von @ user3869936 ist, sehe :methodich den Modus hier in keiner anderen Antwort.

  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

Ergebnis ist:

[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
Kamel Fall ist in der Tat zuerst niedriger. Andernfalls heißt es PascalCase (oder manchmal Großbuchstaben). Auch wenn es in dieser Frage nicht eindeutig ist!
Ulysse BN

2
@UlysseBN, tbh Ich bin nicht in der Geschichte der Wörter. Wikipedia behauptet, PascalCaseist eine Teilmenge von CamelCase. Auch das wusste ich - dieser Kamelfall galt für beide. Aber ich habe nie nachgeforscht. Vielen Dank, dass Sie PascalCase erwähnt haben. en.wikipedia.org/wiki/Camel_case
akostadinov

2
Dies ist die beste Antwort auf der Seite imo. Es wäre schön , wenn die :methodVersion ein tat downcasezunächst so auf beide verwendet werden können , lower_snake_caseund UPPER_SNAKE_CASE.
Skagedal

0

Die meisten anderen hier aufgeführten Methoden sind Rails-spezifisch. Wenn Sie dies mit reinem Ruby tun möchten, ist das Folgende die prägnanteste Methode, die ich mir ausgedacht habe (danke an @ ulysse-bn für die vorgeschlagene Verbesserung).

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

Ihre Definition von "Kamelfall" ist zu begrenzt. Klassennamen in Java und Ruby sind beispielsweise MyFavoriteClass in Kamelschrift ... aber sie haben auch keinen Anfangsbuchstaben in Kleinbuchstaben. manchmal hat Kamel Fall Anfangskappen. manchmal nicht.
Masukomi

Die Verwendung von 2 Regex, bei denen Sie nur einen verwenden können, ist übertrieben. Sie können nur nicht erfassende Gruppen verwenden:x.gsub(/(?:_|^)(\w)/){$1.upcase}
Ulysse BN

@UlysseBN, und wir sind zurück zu Ihrer gsubLösung, die im Vergleich zur mapLösung langsamer zu sein scheint .
Akostadinov

0

Erweitern Sie den String, um Camelize hinzuzufügen

In reinem Ruby können Sie die Zeichenfolgenklasse mit genau demselben Code aus Rails erweitern .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
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.