Conversione di stringhe da snake_case a CamelCase in Ruby


171

Sto cercando di convertire un nome da caso serpente a caso cammello. Ci sono metodi integrati?

Ad esempio: "app_user"a"AppUser"

(Ho una stringa "app_user"che voglio convertire in modello AppUser).

Risposte:


252

Se stai usando Rails, String # camelize è quello che stai cercando.

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

Se vuoi ottenere una classe reale, dovresti usare String # constantize per di più.

"app_user".camelize.constantize

44
Dovresti aggiungere che questa è un'aggiunta di Rails a String, non funziona con Ruby puro.
iGEL

2
È taggato ruby-on-rails, quindi, suppongo, non è un problema. Ma grazie per averlo menzionato.
Sergio Tulentsev,

6
Non è necessario mimetizzarsi prima di eseguire la stabilizzazione. Usa #classifyinvece. "some_namespace/module/class_name".classify => "SomeNamespace::Module::ClassName"
Chris Heald,

5
@chris #classify: non è lo stesso. #classify restituisce una stringa, mentre #constantize cerca costante nel contesto (e ha bisogno di camelize). 'active_record'.constantize restituisce errore,' active_record'.camelize.constantize restituisce la costante ActiveRecord, 'active_record'.classify restituisce la stringa' ActiveRecord '. E se si facesse 'no_class'.camelize.constantize si otterrebbe un errore (nessuna NoClass costante), ma' no_class'.classify restituisce felicemente la stringa 'NoClass'.
Kanat Bolazar,

Per utilizzare questi metodi di Rails dal puro Ruby, require "active_support/core_ext/string"è sufficiente, a condizione che Rails sia già installato.
Masa Sakano,

121

Che ne dici di questo?

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

Si trova nei commenti qui: Classificare una stringa Ruby

Vedi commento di Wayne Conrad


11
Sei fantastico, grazie. Non volevo includere librerie di binari solo per un compito così piccolo. Questo è bellissimo. :)
Gerry,

11
Questa è una delle uniche risposte reali alla domanda. Non utilizzare le librerie Rails.
Luis Ortega Araneda,

40

Se si utilizza Rails, utilizzare classify. Gestisce bene i casi limite.

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

Nota:

Questa risposta è specifica per la descrizione fornita nella domanda (non è specifica per il titolo della domanda). Se si sta cercando di convertire una stringa in una custodia di cammello, dovrebbero usare la risposta di Sergio . L'interrogante afferma che vuole convertirsi app_userin AppUser(non App_user), quindi questa risposta ..


4
Per gli ambienti Rails, questo è perfetto.
Ghayes,

Nota che classifyrestituisce una stringa, devi chiamare in constantizeseguito per convertirla in una classe effettiva.
Stefan,

1
Un avvertimento importante classifyè che le stringhe pluralizzate diventeranno singolari ... 'age_in_years'.classifydiventaAgeInYear
br3nt

@ br3nt non si pluralizza da activerecord4.2.11
Ulysse BN

23

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

Ai fini dell'apprendimento:

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"

E per la variante 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 se la ruota si chiama ActiveSupport , reinventarla.
shime

Penso che la variante di lowerCase sia sbagliata. Il blocco di iniezione non deve manipolare direttamente il buffer ma restituire il nuovo valore per il buffer:self.split('_').inject([]){ |buffer,e| buffer + [buffer.empty? ? e : e.capitalize] }.join
Sven Koschnicke

19

Punto di riferimento per soluzioni Ruby pure

Ho colto tutte le possibilità che avevo in mente per farlo con un codice rubino puro, eccoli qui:

  • capitalizzare e gsub

    'app_user'.capitalize.gsub(/_(\w)/){$1.upcase}
  • dividere e mappare usando la &scorciatoia (grazie alla risposta dell'utente3869936)

    'app_user'.split('_').map(&:capitalize).join
  • dividere e mappare (grazie alla risposta di Mr. Black)

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

Ed ecco il benchmark per tutti questi, possiamo vedere che gsub è abbastanza male per questo. Ho usato 126 080 parole.

                              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

Sono arrivato qui a cercare l'inverso della tua domanda, passando da una custodia per cammelli a una custodia per serpenti. Usa il carattere di sottolineatura per quello (non decamelize):

AppUser.name.underscore # => "app_user"

oppure, se hai già una stringa di custodia di cammello:

"AppUser".underscore # => "app_user"

o, se si desidera ottenere il nome della tabella, è probabilmente il motivo per cui si desidera la custodia del serpente:

AppUser.name.tableize # => "app_users"


Perché non usare AppUser.table_name? Assicurerai anche di avere il vero nome della tabella se non è app_users, ma qualcosa di definito altrove.
Ulysse BN,

3

Mi sento un po 'a disagio ad aggiungere più risposte qui. Ha deciso di optare per l'approccio di rubino puro più leggibile e minimale, ignorando il bel punto di riferimento di @ ulysse-bn. Mentre :classmode è una copia di @ user3869936, la :methodmodalità che non vedo in nessun'altra risposta qui.

  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

Il risultato è:

[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
Il caso del cammello è in effetti il ​​primo più basso. Altrimenti si chiama PascalCase (o talvolta maiuscola). Anche se in questa domanda è ambiguo!
Ulysse BN,

2
@UlysseBN, ma non mi occupo della storia delle parole. Wikipedia afferma che PascalCaseè un sottoinsieme di CamelCase. Anche questo è quello che sapevo: quel caso di cammello si applicava a entrambi. Ma non ho mai indagato. Grazie per aver menzionato PascalCase però. en.wikipedia.org/wiki/Camel_case
akostadinov

2
Questa è la migliore risposta sulla pagina imo. Sarebbe bello se la :methodversione avesse fatto il downcaseprimo in modo che potesse essere utilizzata su entrambi lower_snake_casee UPPER_SNAKE_CASE.
skagedal,

0

La maggior parte degli altri metodi elencati qui sono specifici di Rails. Se vuoi farlo con Ruby puro, il seguente è il modo più conciso che ho escogitato (grazie a @ ulysse-bn per il miglioramento suggerito)

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

La tua definizione di "caso di cammello" è troppo limitata. I nomi delle classi in Java e Ruby, ad esempio, sono MyFavoriteClass maiuscoli di cammello ... ma non hanno nemmeno una lettera iniziale con il maiuscolo. a volte la custodia del cammello ha i tappi iniziali. a volte no.
Masukomi,

L'uso di 2 Regex in cui è possibile utilizzarne solo uno è eccessivo. È possibile utilizzare solo gruppi non acquisiti:x.gsub(/(?:_|^)(\w)/){$1.upcase}
Ulysse BN,

@UlysseBN, e torniamo alla tua gsubsoluzione, sembra più lenta rispetto alla mapsoluzione.
Akostadinov

0

Estendi stringa per aggiungere Camelize

In puro Ruby puoi estendere la classe di stringhe usando lo stesso codice esatto di 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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.