2010-10-22 15 views
27

Ho una bella stringa CamelCase come ImageWideNice o ImageNarrowUgly. Ora voglio rompere quella stringa nelle sottostringhe, ad esempio Image, Wide o Narrow e Nice o Ugly.Come dividere una stringa CamelCase nelle sottostringhe in Ruby?

ho pensato che questo potrebbe essere risolto semplicemente

camelCaseString =~ /(Image)((Wide)|(Narrow))((Nice)|(Ugly))/ 

Ma stranamente, questo sarà solo riempire $1 e $2, ma non $3.

Hai un'idea migliore per suddividere quella stringa?

+1

Cosa vorresti fare con 'ThisIsANarrowImageOfHIV?' Fare un join con n o dividere l'HIV? –

risposta

50
s = 'nowIsTheTime' 

s.split /(?=[A-Z])/ 

=> ["now", "Is", "The", "Time"] 

?=pattern è un esempio di lookahead positivo. Corrisponde essenzialmente a un punto nella stringa subito prima dello schema . Non consuma i personaggi, cioè non include il modello come parte della partita. Un altro esempio:

irb> 'streets'.sub /t(?=s)/, '-' 
=> "stree-s" 

In questo caso il s sia abbinato (soltanto il secondo t partite) ma non sostituito. Grazie alla @Bryce e il suo regexp doc link. Bryce Anderson aggiunge una spiegazione:

Il ?= all'inizio del gruppo () partita è chiamato positiva lookahead, che è solo un modo di dire che, mentre la regex è alla ricerca ai personaggi nel determinare se corrisponde, non è facendoli parte della partita. split() normalmente mangia i caratteri intermedi , ma in questo caso la corrispondenza stessa è vuota, quindi non c'è nulla di [011].

+1

Hai provato "NowIsTheTime'? – splash

+1

@splash: funziona ancora bene – ryeguy

+0

Durante i miei test questa regex risulta in "[" "," Now "," Is "," The "," Time "]' se la prima lettera è una lettera maiuscola. Cosa ho sbagliato? – splash

2

Hai provato

camelCaseString =~ /(Image)(Wide|Narrow)(Nice|Ugly)/ 

?

2

Event anche se questa è una domanda regex Ruby e il answer by DigitalRoss è corretto e brilla per la sua semplicità, voglio aggiungere una risposta Java:

// this regex doesn't work perfect with Java and other regex engines 
"NowIsTheTime".split("(?=[A-Z])"); // ["", "Now", "Is", "The", "Time"] 

// this regex works with first uppercase or lowercase characters 
"NowIsTheTime".split("(?!(^|[a-z]|$))"); // ["Now", "Is", "The", "Time"] 
"nowIsTheTime".split("(?!(^|[a-z]|$))"); // ["now", "Is", "The", "Time"] 
27

So che questo è vecchio, ma vale la pena menzionare per gli altri che potrebbe essere alla ricerca di questo. In rail puoi fare ciò: "NowIsTheTime".underscore.humanize

5

La risposta di DigitalRoss è corretta in quanto gestisce il caso generale in cui non si sa se si tratta di un caso cammello rigoroso (maiuscolo per primo carattere) o caso Pascal (maiuscolo prima lettera).

Se si conosce in quale di queste forme è inserita la stringa o si desidera forzare l'una o l'altra, Inflector può farlo.

Per il caso Pascal:

"NowIsTheTime".titleize 

Per il caso di cammello:

"nowIsTheTime".titleize.camelize :lower 
+0

È importante notare che '# titleize' e' # camelize' sono metodi rigorosamente Rails e non nel core Ruby. – onebree

0

La risposta da DigitalRoss non riconoscerà acronimi incorporati nel CamelCase. Ad esempio, dividerà "MyHTMLTricks" in "My H T M L Tricks" anziché "My HTML Tricks".

Ecco un'altra opzione in base alla funzione AsSpaced() in PmWiki, che fa un grande lavoro di essere sensibili a casi come questo:

"MyHTMLTricks" \ 
.gsub(/([[:lower:]\\d])([[:upper:]])/, '\1 \2') \ 
.gsub(/([^-\\d])(\\d[-\\d]*(|$))/,'\1 \2') \ 
.gsub(/([[:upper:]])([[:upper:]][[:lower:]\\d])/, '\1 \2') 

=> "My HTML Tricks" 

L'altra cosa che mi piace di questo approccio è che lascia la stringa una stringa, invece di trasformarla in un array. Se vuoi veramente la matrice, quindi aggiungi una divisione alla fine.

"MyHTMLTricks" \ 
.gsub(/([[:lower:]\\d])([[:upper:]])/, '\1 \2') \ 
.gsub(/([^-\\d])(\\d[-\\d]*(|$))/,'\1 \2') \ 
.gsub(/([[:upper:]])([[:upper:]][[:lower:]\\d])/, '\1 \2') \ 
.split 

=> ["My", "HTML", "Tricks"] 

Per la cronaca, ecco il codice PHP originale da PmWiki.

function AsSpaced($text) { 
    $text = preg_replace("/([[:lower:]\\d])([[:upper:]])/", '$1 $2', $text); 
    $text = preg_replace('/([^-\\d])(\\d[-\\d]*(|$))/', '$1 $2', $text); 
    return preg_replace("/([[:upper:]])([[:upper:]][[:lower:]\\d])/", '$1 $2', $text); 
} 
Problemi correlati