123 votes

Comment convertir PascalCase en pascal_case ?

Si je l'avais fait :

$string = "PascalCase";

J'ai besoin

"pascal_case"

PHP offre-t-il une fonction à cet effet ?

31 votes

Techniquement, la première chaîne d'exemple est PascalCase.

33 votes

Et le deuxième exemple de chaîne est connu sous le nom de snake_case .

171voto

Jan Jakeš Points 235

Une solution plus courte : Semblable à la de l'éditeur l'un avec une expression régulière simplifiée et en corrigeant le problème du "trailing-underscore" :

$output = strtolower(preg_replace('/(?<!^)[A-Z]/', '_$0', $input));

Démo PHP | Démonstration de Regex


Notez que des cas comme SimpleXML sera converti en simple_x_m_l en utilisant la solution ci-dessus. Cela peut également être considéré comme une mauvaise utilisation de la notation de la casse (la solution correcte serait SimpleXml ) plutôt qu'un bug de l'algorithme puisque de tels cas sont toujours ambigus - même en regroupant les caractères majuscules en une seule chaîne ( simple_xml ), un tel algorithme échouera toujours dans d'autres cas limites tels que XMLHTMLConverter ou des mots d'une lettre près des abréviations, etc. Si vous ne vous préoccupez pas de ces cas limites (plutôt rares) et que vous souhaitez traiter SimpleXML correctement, vous pouvez utiliser une solution un peu plus complexe :

$output = ltrim(strtolower(preg_replace('/[A-Z]([A-Z](?![a-z]))*/', '_$0', $input)), '_');

Démo PHP | Démonstration de Regex

0 votes

N'hésitez pas à commenter la réponse de cletus en détaillant les cas de test que vous avez corrigés.

4 votes

Je ne dis pas que sa solution donne de mauvais résultats. Sa solution est juste extrêmement compliquée et inefficace.

1 votes

Oui, la réponse acceptée est définitivement un échec. La solution de Jan est géniale ! En passant, je pense que ce test (ou une légère variation) est mon nouveau test de codage préféré pour les développeurs PHP, car le nombre de réponses fournies à cette question qui ne fonctionnent pas est incroyable. Ce serait un excellent moyen de faire le filtrage initial :-)

170voto

cletus Points 276888

Essayez-le pour la taille :

$tests = array(
  'simpleTest' => 'simple_test',
  'easy' => 'easy',
  'HTML' => 'html',
  'simpleXML' => 'simple_xml',
  'PDFLoad' => 'pdf_load',
  'startMIDDLELast' => 'start_middle_last',
  'AString' => 'a_string',
  'Some4Numbers234' => 'some4_numbers234',
  'TEST123String' => 'test123_string',
);

foreach ($tests as $test => $result) {
  $output = from_camel_case($test);
  if ($output === $result) {
    echo "Pass: $test => $result\n";
  } else {
    echo "Fail: $test => $result [$output]\n";
  }
}

function from_camel_case($input) {
  preg_match_all('!([A-Z][A-Z0-9]*(?=$|[A-Z][a-z0-9])|[A-Za-z][a-z0-9]+)!', $input, $matches);
  $ret = $matches[0];
  foreach ($ret as &$match) {
    $match = $match == strtoupper($match) ? strtolower($match) : lcfirst($match);
  }
  return implode('_', $ret);
}

Sortie :

Pass: simpleTest => simple_test
Pass: easy => easy
Pass: HTML => html
Pass: simpleXML => simple_xml
Pass: PDFLoad => pdf_load
Pass: startMIDDLELast => start_middle_last
Pass: AString => a_string
Pass: Some4Numbers234 => some4_numbers234
Pass: TEST123String => test123_string

Cela met en œuvre les règles suivantes :

  1. Une séquence commençant par une lettre minuscule doit être suivie de lettres minuscules et de chiffres ;
  2. Une séquence commençant par une lettre majuscule peut être suivie de l'une ou l'autre :
    • une ou plusieurs lettres majuscules et chiffres (suivis soit de la fin de la chaîne, soit d'une lettre majuscule suivie d'une lettre minuscule ou d'un chiffre, soit du début de la séquence suivante) ; ou
    • une ou plusieurs lettres minuscules ou chiffres.

9 votes

Il fonctionne pour les chaînes en casse camel (comme l'a demandé openfrog), mais si vous l'utilisez avec une chaîne en entrée, par exemple "r_id" (déjà "soulignée"), il coupe le préfixe ("r_"). Bonne solution, mais certainement pas universelle.

1 votes

Je suis curieux de savoir pourquoi vous vérifiez si une chaîne de caractères correspond à une chaîne de caractères en majuscules ? Quel est l'avantage de convertir uniquement le premier caractère en minuscules (par opposition à tous les caractères) ?

1 votes

Une solution plus concise qui peut également gérer tous ces cas d'utilisation : stackoverflow.com/a/35719689/4328383

24voto

user644783 Points 151

Porté par le programme de Ruby String#camelize et String#decamelize .

function decamelize($word) {
  return preg_replace(
    '/(^|[a-z])([A-Z])/e', 
    'strtolower(strlen("\\1") ? "\\1_\\2" : "\\2")',
    $word 
  ); 
}

function camelize($word) { 
  return preg_replace('/(^|_)([a-z])/e', 'strtoupper("\\2")', $word); 
}

Une astuce que les solutions ci-dessus ont peut-être oubliée est le modificateur "e" qui fait que preg_replace pour évaluer la chaîne de remplacement en tant que code PHP.

10 votes

Le site e pour preg_replace est déprécié en PHP 5.5.

0 votes

D'ailleurs, ceux-ci ne sont pas non plus dans Ruby, mais dans la bibliothèque d'inflecteurs de Rails - camelize et underscore. api.rubyonrails.org/classes/ActiveSupport/Inflector.html

2 votes

Cela échoue pour "ThisIsATest". Il semble qu'il ne supporte pas deux majuscules consécutives.

22voto

buley Points 7880

La plupart des solutions proposées ici semblent lourdes. Voici ce que j'utilise :

$underscored = strtolower(
    preg_replace(
        ["/([A-Z]+)/", "/_([A-Z]+)([A-Z][a-z])/"], 
        ["_$1", "_$1_$2"], 
        lcfirst($camelCase)
    )
);

"CamelCASE" est converti en "camel_case".

  • lcfirst($camelCase) abaissera le premier caractère (pour éviter que la sortie convertie par 'CamelCASE' ne commence par un trait de soulignement).
  • [A-Z] trouve des lettres majuscules
  • + traitera chaque majuscule consécutive comme un mot (évite que 'CamelCASE' soit converti en camel_C_A_S_E)
  • Le deuxième modèle et le remplacement sont pour ThoseSPECCases -> those_spec_cases au lieu de those_speccases
  • strtolower([…]) met la sortie en minuscules

3 votes

Mais il transforme également CamelCased en _camel_cased.

1 votes

C'est génial - il suffit d'ajouter un substrat commençant au caractère 1 pour contourner ce problème.

4 votes

Excellent ! Il faut juste ajouter lcfirst à la fonction $camelCase

19voto

ekhaled Points 2364

Php n'offre pas de fonction intégrée pour cela, mais voici ce que j'utilise.

function uncamelize($camel,$splitter="_") {
    $camel=preg_replace('/(?!^)[[:upper:]][[:lower:]]/', '$0', preg_replace('/(?!^)[[:upper:]]+/', $splitter.'$0', $camel));
    return strtolower($camel);

}

le séparateur peut être spécifié dans l'appel de la fonction, ainsi vous pouvez l'appeler comme suit

$camelized="thisStringIsCamelized";
echo uncamelize($camelized,"_");
//echoes "this_string_is_camelized"
echo uncamelize($camelized,"-");
//echoes "this-string-is-camelized"

2 votes

Cela échoue pour "ThisIsATest". Il semble qu'il ne supporte pas deux majuscules consécutives.

0 votes

Vous avez sûrement oublié quelque chose car le deuxième remplacement ne fait rien. En dehors de cela, vous pouvez facilement le rendre compatible avec l'unicode avec mb_strtolower et le /u option sur preg_replace .

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X