Comment convertir PascalCase en pascal_case?


Réponses:


163

Essayez ceci 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);
}

Production:

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 soit par:
    • une ou plusieurs lettres et chiffres majuscules (suivis soit de la fin de la chaîne, soit d'une lettre majuscule suivie d'une lettre minuscule ou d'un chiffre, c'est-à-dire le début de la séquence suivante); ou
    • une ou plusieurs lettres ou chiffres minuscules.

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

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

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

156

Une solution plus courte: similaire à celle de l' éditeur avec une expression régulière simplifiée et corrigeant le problème du "trait de soulignement de fin":

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

Démo PHP | Démo Regex


Notez que les cas comme SimpleXMLseront convertis en simple_x_m_lutilisant la solution ci-dessus. Cela peut également être considéré comme une mauvaise utilisation de la notation en cas de chameau (ce serait correct SimpleXml) plutôt qu'un bogue de l'algorithme car de tels cas sont toujours ambigus - même en regroupant les caractères majuscules dans une chaîne ( simple_xml), cet algorithme échouera toujours dans les autres cas extrêmes comme XMLHTMLConverterou mots d' une lettre près abréviations, etc. Si vous ne me dérange pas sur les cas de bord (plutôt rare) et que vous souhaitez gérer SimpleXMLcorrectement, vous pouvez utiliser une solution peu plus complexe:

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

Démo PHP | Démo Regex


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

3
Je ne dis pas que sa solution donne de mauvais résultats. Sa solution est tout simplement extrêmement compliquée et inefficace.
Jan Jakeš

1
Oui, la réponse acceptée est définitivement un échec. La solution de Jan est géniale! En passant, je pense que ceci (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 fonctionne pas réellement est incroyable. Ce serait un excellent moyen d'effectuer le filtrage initial. :-)
JamesG

a trouvé le regex utilisé dans cette solution beaucoup plus complet: stackoverflow.com/questions/2559759/…
thoroc

2
Belle solution pour les cas d'utilisation simples et dans la plupart des cas habituels, cela suffit mais la solution acceptée peut gérer plus de cas d'utilisation, par exemple "simpleXML" peut être converti en "simple_xml" et non en "simple_x_m_l"
Syone

35

Une solution concise et peut gérer certains cas d'utilisation délicats:

function decamelize($string) {
    return strtolower(preg_replace(['/([a-z\d])([A-Z])/', '/([^_])([A-Z][a-z])/'], '$1_$2', $string));
}

Peut gérer tous ces cas:

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
hello_world => hello_world
hello__world => hello__world
_hello_world_ => _hello_world_
hello_World => hello_world
HelloWorld => hello_world
helloWorldFoo => hello_world_foo
hello-world => hello-world
myHTMLFiLe => my_html_fi_le
aBaBaB => a_ba_ba_b
BaBaBa => ba_ba_ba
libC => lib_c

Vous pouvez tester cette fonction ici: http://syframework.alwaysdata.net/decamelize


@VivekVardhan quelle partie de cette expression régulière vous ne comprenez pas?
Syone

Euh, je pense que la minuscule des chaînes non camelcase est un effet secondaire, au cas où la chaîne ne serait pas au format camel case, celle d'origine devrait être retournée. En fait, si vous envoyez 'simple_Text', vous obtenez Fail: simple_Test => simple_Test [simple_test]. La chaîne en minuscules doit être faite uniquement et si seule la chaîne d'origine est une vraie chaîne de casse camel. Qu'en pensez-vous?
guido

24

Porté de Ruby String#camelizeet 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 pu manquer est le modificateur «e» qui permet preg_replaced'évaluer la chaîne de remplacement en tant que code PHP.


10
L' eindicateur pour preg_replaceest obsolète dans PHP 5.5.
cdmckay

BTW 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
mahemoff

2
Cela échoue pour "ThisIsATest". Semble que ne prend pas en charge deux majuscules consécutives.
OnaBai

Juste une note: vous pouvez utiliser lcfirst pour mettre la première lettre en minuscule, alors vous n'avez pas besoin du ^|ou strlen.
Benubird


23

Le composant Symfony Serializer a un CamelCaseToSnakeCaseNameConverter qui a deux méthodes normalize()et denormalize(). Ceux-ci peuvent être utilisés comme suit:

$nameConverter = new CamelCaseToSnakeCaseNameConverter();

echo $nameConverter->normalize('camelCase');
// outputs: camel_case

echo $nameConverter->denormalize('snake_case');
// outputs: snakeCase

1
Il faut se méfier! $nameConverter->normalize('CamelCase')sorties _camel_casedans la version actuelle 3.2 du composant Symfony Serializer.
spackmat

21

La plupart des solutions 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 (évite que la sortie convertie 'CamelCASE' commence par un trait de soulignement)
  • [A-Z] trouve les majuscules
  • + traitera chaque majuscule consécutive comme un mot (évite que 'CamelCASE' soit converti en camel_C_A_S_E)
  • Le deuxième motif et le remplacement sont pour ThoseSPECCases-> those_spec_casesau lieu dethose_speccases
  • strtolower([…]) transforme la sortie en minuscules

3
Mais cela transforme également CamelCased en _camel_cased.
acme

1
c'est génial - ajoutez simplement une sous-chaîne commençant à char 1 pour contourner ce problème.
Oddman

4
Excellent! Juste besoin d'ajouter une lcfirstfonction à $ camelCase
Edakos

La réponse acceptée traitera: TestUPSClass en test_ups_class alors que cela le transformera en test_u_p_s_class, quelque chose à garder à l'esprit.
Mazzy

Une chaîne d'entrée qui commence par un premier «mot» allcaps sera fractionnée de manière inattendue par cette solution en raison de l' ucfirst()appel. USADollarSymboldevient u_sa_dollar_symbol Demo Je ne recommande pas cette solution car elle doit faire deux passes dans la chaîne d'entrée avec regex - un signe d'un modèle non raffiné.
mickmackusa

19

php n'offre pas de fonction intégrée pour cet afaik, 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 fonction, vous pouvez donc l'appeler comme ceci

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

2
Cela échoue pour "ThisIsATest". Semble que ne prend pas en charge deux majuscules consécutives.
OnaBai

Vous avez sûrement oublié quelque chose car le deuxième remplaçant ne fait rien. En dehors de cela, vous pouvez facilement le rendre compatible Unicode avec mb_strtoloweret l' /uoption activée preg_replace.
bodo

8

Vous devez exécuter une expression régulière qui correspond à toutes les lettres majuscules sauf si elle est au début et la remplacer par un trait de soulignement plus cette lettre. Une solution utf-8 est la suivante:

header('content-type: text/html; charset=utf-8');
$separated = preg_replace('%(?<!^)\p{Lu}%usD', '_$0', 'AaaaBbbbCcccDdddÁáááŐőőő');
$lower = mb_strtolower($separated, 'utf-8');
echo $lower; //aaaa_bbbb_cccc_dddd_áááá_őőőő

Si vous n'êtes pas sûr de la casse de votre chaîne, mieux vaut la vérifier d'abord, car ce code suppose que l'entrée est à la camelCaseplace de underscore_Caseou dash-Case, donc si les derniers ont des lettres majuscules, il leur ajoutera des traits de soulignement.

La réponse acceptée de cletus est beaucoup trop compliquée à mon humble avis et cela ne fonctionne qu'avec les caractères latins. Je trouve que c'est une très mauvaise solution et je me demande pourquoi elle a été acceptée. La conversion TEST123Stringen test123_stringn'est pas nécessairement une exigence valable. Je l'ai plutôt gardé simple et séparé ABCcccen a_b_ccccau lieu de ab_ccccparce qu'il ne perd pas d'informations de cette façon et la conversion vers l'arrière donnera exactement la même chaîne avec laquelle nous avons commencé. Même si vous voulez le faire dans l'autre sens, il est relativement facile d'écrire une expression régulière pour elle avec un (?<!^)\p{Lu}\p{Ll}|(?<=\p{Ll})\p{Lu}regard en arrière positif ou deux expressions régulières sans regarder en arrière si vous n'êtes pas un expert en expression régulière. Il n'est pas nécessaire de le diviser en sous-chaînes sans parler du choix entre strtoloweret lcfirstoù l'utilisation strtolowerserait tout à fait correcte.


Les réponses basées uniquement sur le code sont de faible valeur sur Stackoverflow, car elles ne font pas grand-chose pour éduquer / autonomiser des milliers de futurs chercheurs.
mickmackusa

@mickmackusa Si les chercheurs apprennent à coder à partir de SO, alors nous avons un sérieux problème ...
inf3rno

Maintenant que vous avez éliminé cette attaque personnelle de votre système, veuillez améliorer votre réponse. En supposant que vous sachiez comment votre solution fonctionne et pourquoi vous utilisez ces modificateurs de modèle, je ne vois aucune bonne raison de retenir les connaissances de cette communauté. Au cas où vous envisagez de laisser des réponses plus sournoises, je vous assure qu'elles ne me dérangent pas. Pendant le temps que vous avez pris pour commenter, vous auriez pu compléter votre réponse, nous aurions pu supprimer nos commentaires, et j'aurais pu aller ailleurs pour aider ce site.
mickmackusa

Bien sûr, je n'ai pas le pouvoir de supprimer un message avec 8 votes positifs. Si vous le souhaitez, vous pouvez supprimer votre réponse, mais il ne serait pas très difficile de l'améliorer simplement en supprimant les modificateurs de motif inutiles et en ajoutant une explication. Les attaques personnelles n'ont aucun effet sur moi.
mickmackusa

@mickmackusa Je ne pense pas pouvoir le supprimer non plus. N'hésitez pas à le modifier si vous le souhaitez.
inf3rno

6

Si vous recherchez une version PHP 5.4 et une réponse ultérieure, voici le code:

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

}
function camelize($word) {
    return $word = preg_replace_callback(
        "/(^|_)([a-z])/",
        function($m) { return strtoupper("$m[2]"); },
        $word
    );

} 

camelize produit "SmsSent" pour sms_sent, vous avez besoin d'un lcfirst
mik3fly-4steri5k

4

Pas du tout fantaisiste mais simple et rapide comme l'enfer:

function uncamelize($str) 
{
    $str = lcfirst($str);
    $lc = strtolower($str);
    $result = '';
    $length = strlen($str);
    for ($i = 0; $i < $length; $i++) {
        $result .= ($str[$i] == $lc[$i] ? '' : '_') . $lc[$i];
    }
    return $result;
}

echo uncamelize('HelloAWorld'); //hello_a_world

++$iau lieu de $i++le rendre un peu plus rapide aussi;)
Mathieu Amiot

Les réponses basées uniquement sur le code sont de faible valeur sur Stackoverflow, car elles ne font pas grand-chose pour éduquer / autonomiser des milliers de futurs chercheurs.
mickmackusa

4

"CamelCase" à "camel_case":

function camelToSnake($camel)
{
    $snake = preg_replace('/[A-Z]/', '_$0', $camel);
    $snake = strtolower($snake);
    $snake = ltrim($snake, '_');
    return $snake;
}

ou:

function camelToSnake($camel)
{
    $snake = preg_replace_callback('/[A-Z]/', function ($match){
        return '_' . strtolower($match[0]);
    }, $camel);
    return ltrim($snake, '_');
}

Je vous remercie. J'ai utilisé la première approche, mais avec des tirets pour générerthis-kind-of-output
thexpand

3

Une version qui n'utilise pas regex peut être trouvée dans la source Alchitect :

decamelize($str, $glue='_')
{
    $counter  = 0;
    $uc_chars = '';
    $new_str  = array();
    $str_len  = strlen($str);

    for ($x=0; $x<$str_len; ++$x)
    {
        $ascii_val = ord($str[$x]);

        if ($ascii_val >= 65 && $ascii_val <= 90)
        {
            $uc_chars .= $str[$x];
        }
    }

    $tok = strtok($str, $uc_chars);

    while ($tok !== false)
    {
        $new_char  = chr(ord($uc_chars[$counter]) + 32);
        $new_str[] = $new_char . $tok;
        $tok       = strtok($uc_chars);

        ++$counter;
    }

    return implode($new_str, $glue);
}

2
Voici à quoi ressemblerait la vie sans regex :-)
ekhaled

4
Heh, ouais. RegEx a définitivement ses avantages. :) La vitesse brute n'en fait pas partie.
Darrell Brogdon

obtenu des résultats amusants avec celui-ci pour une raison quelconque
mr1031011

Ne fonctionne pas pour moi basé sur cette chaîne: "CamelCaseTestAAATestAA", devrait avoir: "camel_case_test_a_a_a_test_a_a", a: "" camel_case_test_aest "...
Sybio

3

Voici donc un one-liner:

strtolower(preg_replace('/(?|([a-z\d])([A-Z])|([^\^])([A-Z][a-z]))/', '$1_$2', $string));

Bien, mais cela ne convertit que la première apparence, je vous recommande donc d'ajouter un gmodificateur à cette expression régulière.
acme

@acme, je l'utilise sans get cela fonctionne très bien pour moi.
seelts le

Pour une raison quelconque, dans mon cas, j'ai dû ajouter le fichier g. Mais je ne me souviens pas de la phrase avec laquelle j'ai testé.
acme


3

Laravel 5.6 fournit un moyen très simple de le faire:

 /**
 * Convert a string to snake case.
 *
 * @param  string  $value
 * @param  string  $delimiter
 * @return string
 */
public static function snake($value, $delimiter = '_'): string
{
    if (!ctype_lower($value)) {
        $value = strtolower(preg_replace('/(.)(?=[A-Z])/u', '$1'.$delimiter, $value));
    }

    return $value;
}

Ce qu'il fait: s'il voit qu'il y a au moins une lettre majuscule dans la chaîne donnée, il utilise une anticipation positive pour rechercher n'importe quel caractère ( .) suivi d'une majuscule ( (?=[A-Z])). Il remplace ensuite le caractère trouvé par sa valeur suivie du séparateur _.


Cette fonction semble maintenant s'appeler snake_case () et vit dans l'espace de noms global.
Wotuu

2

Le port direct depuis les rails (moins leur traitement spécial pour :: ou les acronymes) serait

function underscore($word){
    $word = preg_replace('#([A-Z\d]+)([A-Z][a-z])#','\1_\2', $word);
    $word = preg_replace('#([a-z\d])([A-Z])#', '\1_\2', $word);
    return strtolower(strtr($word, '-', '_'));
}

Connaissant PHP, ce sera plus rapide que l'analyse manuelle qui se produit dans d'autres réponses données ici. L'inconvénient est que vous ne pouvez pas choisir ce qu'il faut utiliser comme séparateur entre les mots, mais cela ne faisait pas partie de la question.

Vérifiez également le code source des rails pertinents

Notez que ceci est destiné à être utilisé avec les identificateurs ASCII. Si vous devez faire cela avec des caractères en dehors de la plage ASCII, utilisez le modificateur '/ u' pour preg_matchet utilisez mb_strtolower.


Vous pouvez, si vous ajoutez simplement un paramètre contenant le caractère souhaité.
Fleshgrinder

2

Voici ma contribution à une question de six ans avec Dieu sait combien de réponses ...

Il convertira tous les mots de la chaîne fournie qui sont dans camelcase en snakecase. Par exemple, "SuperSpecialAwesome et aussi FizBuzz καιΚάτιΑκόμα" seront convertis en "super_special_awesome et aussi fizz_buzz και_κάτι_ακόμα".

mb_strtolower(
    preg_replace_callback(
        '/(?<!\b|_)\p{Lu}/u',
        function ($a) {
            return "_$a[0]";
        },
        'SuperSpecialAwesome'
    )
);

2

Yii2 a la fonction différente pour créer le mot snake_case de CamelCase.

    /**
     * Converts any "CamelCased" into an "underscored_word".
     * @param string $words the word(s) to underscore
     * @return string
     */
    public static function underscore($words)
    {
        return strtolower(preg_replace('/(?<=\\w)([A-Z])/', '_\\1', $words));
    }

2

Solution courte:

$subject = "PascalCase";
echo strtolower(preg_replace('/\B([A-Z])/', '_$1', $subject));

2

J'ai eu un problème similaire mais je n'ai trouvé aucune réponse satisfaisant la conversion de CamelCase en snake_case, tout en évitant les traits de soulignement en double ou redondants _pour les noms avec des traits de soulignement ou les abréviations en majuscules.

Le problème est le suivant:

CamelCaseClass            => camel_case_class
ClassName_WithUnderscores => class_name_with_underscore
FAQ                       => faq

La solution que j'ai écrite est un simple appel à deux fonctions, minuscules et rechercher et remplacer des lettres minuscules-majuscules consécutives:

strtolower(preg_replace("/([a-z])([A-Z])/", "$1_$2", $name));

C'est de loin la solution la plus concise et la plus utile de l'OMI.
Mr.Shan0

1
function camel2snake($name) {
    $str_arr = str_split($name);
    foreach ($str_arr as $k => &$v) {
        if (ord($v) >= 64 && ord($v) <= 90) { // A = 64; Z = 90
            $v = strtolower($v);
            $v = ($k != 0) ? '_'.$v : $v;
        }
    }
    return implode('', $str_arr);
}

Vous pouvez accéder aux caractères directement en utilisant $name{$k}(ou $name[$k]), ce qui allongerait votre code, mais évite la surcharge de le convertir vers et à partir d'un tableau.
bodo

Les réponses basées uniquement sur le code ont une faible valeur sur StackOverflow car elles ne permettent pas de responsabiliser / éduquer les futurs chercheurs. Votre solution, tout en évitant la grâce des regex, est très lourde et alambiquée. Vous divisez sur chaque caractère et effectuez plusieurs appels de fonction itérés. Nommer une chaîne vide comme colle n'est pas nécessaire. Je n'entrerais pas dans cette solution dans l'un de mes projets car il n'y a pas d'élégance, une faible lisibilité et un nombre n d'appels de fonctions inutiles.
mickmackusa

1

La pire réponse ici était si proche d'être la meilleure (utilisez un cadre). NON NE PAS, jetez un œil au code source. voir ce qu'un cadre bien établi utilise serait une approche beaucoup plus fiable (éprouvée et testée). Le framework Zend a quelques filtres de mots qui correspondent à vos besoins. Source .

voici quelques méthodes que j'ai adaptées de la source.

function CamelCaseToSeparator($value,$separator = ' ')
{
    if (!is_scalar($value) && !is_array($value)) {
        return $value;
    }
    if (defined('PREG_BAD_UTF8_OFFSET_ERROR') && preg_match('/\pL/u', 'a') == 1) {
        $pattern     = ['#(?<=(?:\p{Lu}))(\p{Lu}\p{Ll})#', '#(?<=(?:\p{Ll}|\p{Nd}))(\p{Lu})#'];
        $replacement = [$separator . '\1', $separator . '\1'];
    } else {
        $pattern     = ['#(?<=(?:[A-Z]))([A-Z]+)([A-Z][a-z])#', '#(?<=(?:[a-z0-9]))([A-Z])#'];
        $replacement = ['\1' . $separator . '\2', $separator . '\1'];
    }
    return preg_replace($pattern, $replacement, $value);
}
function CamelCaseToUnderscore($value){
    return CamelCaseToSeparator($value,'_');
}
function CamelCaseToDash($value){
    return CamelCaseToSeparator($value,'-');
}
$string = CamelCaseToUnderscore("CamelCase");

1

Il existe une bibliothèque offrant cette fonctionnalité:

SnakeCaseFormatter::run('CamelCase'); // Output: "camel_case"

1
Je pense que vous voulez dire "j'ai créé une bibliothèque fournissant cette fonctionnalité". Rien de mal avec l'auto-promotion, mais ne le cachez pas.
icc97


1

C'est l'un des moyens les plus courts:

function camel_to_snake($input)
{
    return strtolower(ltrim(preg_replace('/([A-Z])/', '_\\1', $input), '_'));
}

Les réponses basées uniquement sur le code sont de faible valeur sur Stackoverflow, car elles ne font pas grand-chose pour éduquer / autonomiser des milliers de futurs chercheurs.
mickmackusa

1
@mickmackusa - des milliers de recherches futures seront intéressées par un one-liner élégant et s'éduqueront.
Teson

Je suis désolé que vous ayez adopté cette position égoïste. Vous auriez certainement pu ajouter une explication sur le temps qu'il vous a fallu pour concevoir et taper cette réponse sarcastique. Votre réponse fait trois appels de fonction, mais d'autres exécutent la tâche en deux.
mickmackusa

1

Comment dé-caméliser sans utiliser regex:

function decamelize($str, $glue = '_') {
    $capitals = [];
    $replace  = [];

    foreach(str_split($str) as $index => $char) {
        if(!ctype_upper($char)) {
            continue;
        }

        $capitals[] = $char;
        $replace[]  = ($index > 0 ? $glue : '') . strtolower($char);
    }

    if(count($capitals) > 0) {
        return str_replace($capitals, $replace, $str);
    }

    return $str;
}

Une modification:

Comment pourrais-je faire cela en 2019:

function toSnakeCase($str, $glue = '_') {
    return preg_replace_callback('/[A-Z]/', function ($matches) use ($glue) {
        return $glue . strtolower($matches[0]);
    }, $str);
}

Et quand PHP 7.4 sortira:

function toSnakeCase($str, $glue = '_') {
    return preg_replace_callback('/[A-Z]/', fn($matches) => $glue . strtolower($matches[0]), $str);
}

1
Les réponses basées uniquement sur le code ont une faible valeur sur StackOverflow car elles ne permettent pas de responsabiliser / éduquer les futurs chercheurs. Faire 1 à 3 appels de fonction sur chaque caractère de la chaîne, puis deux autres appels de fonction une fois la boucle terminée, est très lourd. Je ne voudrais pas envisager une solution avec une économie aussi médiocre.
mickmackusa

C'est un exemple de comment cela pourrait être fait sans utiliser d'expressions régulières, pas comment cela devrait être utilisé en production, donc je ne vois pas votre point en plus que vous vous plaignez d'une réponse 5y / o qui a un vote positif et est peu susceptible d'être vue par tous les chercheurs.
baldrs

Je porte mon attention sur tous les messages, pas seulement ceux qui ont reçu un vote très positif ou ceux qui sont récents. Je ne me plains pas, j'offre ma critique pour que les chercheurs ayant moins de connaissances puissent mieux comprendre la différence entre cette réponse et d'autres réponses. Vous auriez pu expliquer dans votre message qu'il s'agissait simplement d'un défi académique pour éviter les regex. Cela dit, il existe des moyens de rendre ce processus plus efficace grâce à de meilleures pratiques de codage.
mickmackusa

0

C'est facile d'utiliser les classes Filter des Zend Word Filters :

<?php
namespace MyNamespace\Utility;

use Zend\Filter\Word\CamelCaseToUnderscore;
use Zend\Filter\Word\UnderscoreToCamelCase;

class String
{
    public function test()
    {
        $underscoredStrings = array(
            'simple_test',
            'easy',
            'html',
            'simple_xml',
            'pdf_load',
            'start_middle_last',
            'a_string',
            'some4_numbers234',
            'test123_string',
        );
        $camelCasedStrings = array(
            'simpleTest',
            'easy',
            'HTML',
            'simpleXML',
            'PDFLoad',
            'startMIDDLELast',
            'AString',
            'Some4Numbers234',
            'TEST123String',
        );
        echo PHP_EOL . '-----' . 'underscoreToCamelCase' . '-----' . PHP_EOL;
        foreach ($underscoredStrings as $rawString) {
            $filteredString = $this->underscoreToCamelCase($rawString);
            echo PHP_EOL . $rawString . ' >>> ' . $filteredString . PHP_EOL;
        }
        echo PHP_EOL . '-----' . 'camelCaseToUnderscore' . '-----' . PHP_EOL;
        foreach ($camelCasedStrings as $rawString) {
            $filteredString = $this->camelCaseToUnderscore($rawString);
            echo PHP_EOL . $rawString . ' >>> ' . $filteredString . PHP_EOL;
        }
    }

    public function camelCaseToUnderscore($input)
    {
        $camelCaseToSeparatorFilter = new CamelCaseToUnderscore();
        $result = $camelCaseToSeparatorFilter->filter($input);
        $result = strtolower($result);
        return $result;
    }

    public function underscoreToCamelCase($input)
    {
        $underscoreToCamelCaseFilter = new UnderscoreToCamelCase();
        $result = $underscoreToCamelCaseFilter->filter($input);
        return $result;
    }
}

----- soulignéToCamelCase -----

simple_test >>> SimpleTest

facile >>> Facile

html >>> Html

simple_xml >>> SimpleXml

pdf_load >>> PdfLoad

start_middle_last >>> StartMiddleLast

a_string >>> AString

some4_numbers234 >>> Some4Numbers234

test123_string >>> Test123String

----- camelCaseToUnderscore -----

simpleTest >>> simple_test

facile >>> facile

HTML >>> html

simpleXML >>> simple_xml

PDFLoad >>> pdf_load

startMIDDLELast >>> start_middle_last

AString >>> a_string

Some4Numbers234 >>> some4_numbers234

TEST123String >>> test123_string


0

La bibliothèque open source TurboCommons contient une méthode formatCase () à usage général dans la classe StringUtils, qui vous permet de convertir une chaîne en de nombreux formats de cas courants, tels que CamelCase, UpperCamelCase, LowerCamelCase, snake_case, Title Case, et bien d'autres.

https://github.com/edertone/TurboCommons

Pour l'utiliser, importez le fichier phar dans votre projet et:

use org\turbocommons\src\main\php\utils\StringUtils;

echo StringUtils::formatCase('camelCase', StringUtils::FORMAT_SNAKE_CASE);

// will output 'camel_Case'

0
$str = 'FooBarBaz';

return strtolower(preg_replace('~(?<=\\w)([A-Z])~', '_$1', $str)); // foo_bar_baz

1
Les réponses basées uniquement sur le code ont une faible valeur sur StackOverflow car elles ne permettent pas de responsabiliser / éduquer les futurs chercheurs.
mickmackusa

-1

SI vous pouviez commencer par:

$string = 'Camel_Case'; // underscore or any other separator...

Ensuite, vous pouvez convertir dans les deux cas simplement avec:

$pascal = str_replace("_", "", $string);
$snake = strtolower($string);

Ou tout autre cas:

$capitalized = str_replace("_", " ", $string); // Camel Case
$constant = strtoupper($string);               // CAMEL_CASE
$train = str_replace("_", "-", $snake);        // camel-case
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.