Comment convertir PascalCase à pascal_case?
-
22-09-2019 - |
Question
Si je devais:
$string = "PascalCase";
Je dois
"pascal_case"
Est-ce que PHP offre une fonction à cet effet?
La solution
Essayez ceci sur 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
met en œuvre les règles suivantes:
- Une séquence commençant par une lettre minuscule doit être suivie par des lettres minuscules et chiffres;
- peut suivre une séquence commençant par une lettre majuscule soit par:
- une ou plusieurs lettres majuscules et des chiffres (suivi soit par la fin de la chaîne ou une lettre majuscule suivie par une lettre minuscule ou un chiffre-à-dire le début de la séquence suivante); ou
- une ou plusieurs lettres ou chiffres minuscules.
Autres conseils
Une solution plus courte: Similaire à éditeur de une avec une expression régulière simplifiée et régler le problème "de fuite-underscore":
$output = strtolower(preg_replace('/(?<!^)[A-Z]/', '_$0', $input));
Notez que des cas comme SimpleXML
seront convertis 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 cas de chameau (correct serait SimpleXml
) plutôt que d'un bug de l'algorithme car ces cas sont toujours ambigus - même en regroupant les caractères majuscules à une chaîne (simple_xml
) tel algorithme sera toujours échouer dans d'autres cas de pointe comme des mots XMLHTMLConverter
ou à une lettre près des abréviations, etc. Si vous ne me dérange pas sur les cas de bord (plutôt rare) et que vous souhaitez gérer correctement SimpleXML
, vous pouvez utiliser une solution peu plus complexe:
$output = ltrim(strtolower(preg_replace('/[A-Z]([A-Z](?![a-z]))*/', '_$0', $input)), '_');
Une solution concise et peut traiter certains cas d'utilisation délicate:
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 ici cette fonction: http://syframework.alwaysdata.net/decamelize
Ported de la String#camelize
et String#decamelize
Ruby.
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 les solutions ci-dessus peut-être manqué est le modificateur « e » qui provoque preg_replace
d'évaluer la chaîne de remplacement code PHP.
La composante Symfony sérialiseur a 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
La plupart des solutions ici sentent la main lourde. 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 de la camelcase 'sortie convertie commencer par un trait de soulignement) -
[A-Z]
trouve des lettres majuscules -
+
traitera chaque majuscule consécutive comme mot ( « évite camelcase » à convertir en camel_C_A_S_E) - Second motif et le remplacement sont pour
ThoseSPECCases
->those_spec_cases
au lieu dethose_speccases
-
strtolower([…])
tourne la sortie à bas de casse
php ne propose pas construit en fonction de ce 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, de sorte que vous pouvez l'appeler comme si
$camelized="thisStringIsCamelized";
echo uncamelize($camelized,"_");
//echoes "this_string_is_camelized"
echo uncamelize($camelized,"-");
//echoes "this-string-is-camelized"
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 cherchez une version PHP 5.4 et répondre plus tard 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
);
}
Pas de fantaisie du tout, 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
"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, '_');
}
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);
}
Voici donc un one-liner:
strtolower(preg_replace('/(?|([a-z\d])([A-Z])|([^\^])([A-Z][a-z]))/', '$1_$2', $string));
danielstjules / Stringy provieds un procédé pour convertir la chaîne de camelcase à snake case.
s('TestUCase')->underscored(); // 'test_u_case'
Laravel 5.6 fournit un moyen très simple de faire ceci:
/**
* 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: si elle voit qu'il ya au moins une lettre majuscule dans la chaîne donnée, il utilise un positif pour rechercher préanalyse tout caractère (.
) suivi d'une lettre capitale ((?=[A-Z])
). Il remplace alors le caractère trouvé avec sa valeur suivie par la _
de separactor.
Le port direct de rails (moins leur traitement spécial pour :: ou 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, '-', '_'));
}
Savoir PHP, ce sera plus rapide que l'analyse syntaxique manuel qui se passe dans d'autres réponses ici. L'inconvénient est que vous ne recevez pas de choisir ce qu'il faut utiliser comme séparateur entre les mots, mais qui ne faisait pas partie de la question.
Vérifiez également la de code
Notez que cela est destiné à être utilisé avec des identificateurs ASCII. Si vous devez le faire avec des caractères en dehors de la plage ASCII, utilisez le modificateur « / u » pour preg_match
mb_strtolower
and d'utilisation.
Voici ma contribution à une question de six ans avec Dieu sait combien de réponses ...
Il convertit tous les mots dans la chaîne fournie qui sont dans camelcase à snake case. Par exemple "SuperSpecialAwesome et aussi FizBuzz καιΚάτιΑκόμα" sera converti en "super_special_awesome et aussi fizz_buzz και_κάτι_ακόμα".
mb_strtolower(
preg_replace_callback(
'/(?<!\b|_)\p{Lu}/u',
function ($a) {
return "_$a[0]";
},
'SuperSpecialAwesome'
)
);
Yii2 ont les différentes fonctions pour rendre 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));
}
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);
}
Il y a un offrant cette fonctionnalité:
SnakeCaseFormatter::run('CamelCase'); // Output: "camel_case"
Si vous utilisez cadre Laravel, vous pouvez utiliser simplement snake_case () méthode.
$str = 'FooBarBaz';
return strtolower(preg_replace('~(?<=\\w)([A-Z])~', '_$1', $str)); // foo_bar_baz
Ceci est l'une des façons plus courtes:
function camel_to_snake($input)
{
return strtolower(ltrim(preg_replace('/([A-Z])/', '_\\1', $input), '_'));
}
Comment dé-camelize 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;
}
Un edit:
Comment puis-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 sera disponible:
function toSnakeCase($str, $glue = '_') {
return preg_replace_callback('/[A-Z]/', fn($matches) => $glue . strtolower($matches[0]), $str);
}
Solution à court:
$subject = "PascalCase";
echo strtolower(preg_replace('/\B([A-Z])/', '_$1', $subject));
Il est facile à l'aide des classes de filtre du Zend Mot filtres :
<?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;
}
}
----- ----- underscoreToCamelCase
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
La pire réponse ici était si près d'être le meilleur (utiliser un cadre). NON NE, jetez un coup d'oeil au code source. voyant ce qu'est un cadre des utilisations bien établies seraient une approche beaucoup plus fiable (essayé et testé). Zend Framework a des filtres de mots qui correspondent à vos besoins. source.
Voici quelques méthodes que j'ADAPTÉ 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");
La bibliothèque de TurboCommons open source contient une méthode polyvalente formatCase () dans la classe StringUtils, ce qui vous permet de convertir une chaîne à beaucoup de formats de cas communs, comme CamelCase, UpperCamelCase, lowerCamelCase, snake_case, Titre du cas, et beaucoup d'autres.
https://github.com/edertone/TurboCommons
Pour l'utiliser, importer le fichier phar à votre projet et:
use org\turbocommons\src\main\php\utils\StringUtils;
echo StringUtils::formatCase('camelCase', StringUtils::FORMAT_SNAKE_CASE);
// will output 'camel_Case'
J'ai eu un problème similaire mais ne pouvait pas trouver une réponse qui satisfait comment convertir CamelCase à snake_case, tout en évitant de dupliquer ou redondantes pour les noms des underscores _
avec des underscores, ou toutes les abréviations caps.
Th problème est comme suit:
CamelCaseClass => camel_case_class
ClassName_WithUnderscores => class_name_with_underscore
FAQ => faq
La solution que j'ai écrit est un deux simples fonctions d'appel, minuscules et rechercher et remplacer les lettres minuscules en majuscules consécutives:
strtolower(preg_replace("/([a-z])([A-Z])/", "$1_$2", $name));
Si vous pouviez commencer par:
$string = 'Camel_Case'; // underscore or any other separator...
Ensuite, vous pouvez convertir en deux cas seulement 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