2010-10-22 1 views
27

J'ai une belle chaîne de CamelCase telle que ImageWideNice ou ImageNarrowUgly. Maintenant, je veux casser cette chaîne dans ses sous-chaînes, telles que Image, Wide ou Narrow, et Nice ou Ugly.Comment diviser une chaîne CamelCase dans ses sous-chaînes dans Ruby?

Je pensais que cela pourrait être résolu simplement par

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

Mais étrangement, cela ne remplir $1 et $2, mais pas $3.

Avez-vous une meilleure idée pour diviser cette chaîne?

+1

Que voudriez-vous fait avec 'ThisIsANarrowImageOfHIV?' Faire une jointure avec n, ou diviser le VIH? –

Répondre

50
s = 'nowIsTheTime' 

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

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

?=pattern est un exemple de avant positive. Il correspond essentiellement à un point de la chaîne juste avant le modèle . Il ne consomme pas les caractères, c'est à dire, il ne comprend pas modèle dans le cadre du match. Un autre exemple:

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

Dans ce cas, le s est mis en correspondance (seulement la deuxième t matches) mais pas remplacé. Merci à @Bryce et son regexp doc link. Bryce Anderson ajoute une explication:

Le ?= au début du groupe match () est appelé positif préanalyse, qui est juste une façon de dire que, si l'expression régulière est recherche aux caractères pour déterminer si cela correspond, ce n'est pas qui fait partie du match. split() mange normalement l'entre caractères, mais dans ce cas, le match lui-même est vide, donc il n'y a rien [il].

+1

Avez-vous essayé 'NowIsTheTime'? – splash

+1

@splash: ça marche toujours bien – ryeguy

+0

Pendant mes tests, cette regex a pour résultat '[" "," Maintenant "," Est "," Le "," Heure "]' si la première lettre est une lettre majuscule. Qu'est-ce que j'ai tort? – splash

2

Avez-vous essayé

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

?

2

événement bien que ce soit une question Ruby regex et la answer by DigitalRoss est correcte et brille par sa simplicité, je veux ajouter une réponse 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

Je sais que c'est vieux, mais vaut la peine de mentionner pour d'autres qui pourrait être à la recherche de cela. Dans les rails, vous pouvez le faire: "NowIsTheTime".underscore.humanize

5

La réponse de DigitalRoss est correcte car elle gère le cas général où vous ne savez pas si c'est rigoureux chameau (premier caractère minuscule) ou Pascal cas (première lettre majuscule).

Si vous connaissez la forme de la chaîne ou si vous voulez forcer l'une ou l'autre, Inflector peut le faire.

Pour le cas Pascal:

"NowIsTheTime".titleize 

Pour le cas de chameau:

"nowIsTheTime".titleize.camelize :lower 
+0

Important à noter, '# titleize' et' # camelize' sont strictement des méthodes Rails, et pas dans le noyau Ruby. – onebree

0

La réponse de DigitalRoss ne reconnaîtra pas les acronymes intégrés dans le CamelCase. Par exemple, il divisera "MyHTMLTricks" en "My H T M L Tricks" au lieu de "My HTML Tricks".

Voici une autre option basée sur la fonction AsSpaced() dans PmWiki, qui fait un excellent travail d'être sensible aux cas comme celui-ci:

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

=> "My HTML Tricks" 

L'autre chose que j'aime cette approche est qu'elle laisse la chaîne une chaîne, au lieu de la transformer en tableau. Si vous voulez vraiment le tableau, alors ajoutez juste un split à la fin.

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

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

Pour l'enregistrement, voici le code PHP original de 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); 
} 
Questions connexes