php - que - Cómo convertir CamelCase a camel_case?
primer letra de cada palabra en mayuscula php (25)
Si tuviera:
$string = "CamelCase";
Necesito
"camel_case"
¿PHP ofrece una función para este propósito?
"CamelCase" a "camel_case":
function camelToSnake($camel)
{
$snake = preg_replace(''/[A-Z]/'', ''_$0'', $camel);
$snake = strtolower($snake);
$snake = ltrim($snake, ''_'');
return $snake;
}
o:
function camelToSnake($camel)
{
$snake = preg_replace_callback(''/[A-Z]/'', function ($match){
return ''_'' . strtolower($match[0]);
}, $camel);
return ltrim($snake, ''_'');
}
Aquí está mi contribución a una pregunta de seis años con Dios sabe cuántas respuestas ...
Convertirá todas las palabras en la cadena proporcionada que están en camelcase en snakecase. Por ejemplo, "SuperSpecialAwesome y también FizBuzz καιΚάτιΑκόμα" se convertirán en "super_special_awesome y también fizz_buzz και_κάτι_ακόμα".
mb_strtolower(
preg_replace_callback(
''/(?<!/b|_)/p{Lu}/u'',
function ($a) {
return "_$a[0]";
},
''SuperSpecialAwesome''
)
);
Así que aquí hay un trazador de líneas:
strtolower(preg_replace(''/(?|([a-z/d])([A-Z])|([^/^])([A-Z][a-z]))/'', ''$1_$2'', $string));
El componente de serializador Symfony tiene un CamelCaseToSnakeCaseNameConverter que tiene dos métodos normalize()
y denormalize()
. Estos se pueden usar de la siguiente manera:
$nameConverter = new CamelCaseToSnakeCaseNameConverter();
echo $nameConverter->normalize(''camelCase'');
// outputs: camel_case
echo $nameConverter->denormalize(''snake_case'');
// outputs: snakeCase
El puerto directo de los rieles (menos su manejo especial para :: o acrónimos) sería
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, ''-'', ''_''));
}
Conociendo PHP, esto será más rápido que el análisis manual que está sucediendo en otras respuestas dadas aquí. La desventaja es que no puede elegir qué usar como separador entre palabras, pero eso no formaba parte de la pregunta.
También verifique el código fuente de los raíles relevantes
Tenga en cuenta que esto está destinado a ser utilizado con identificadores ASCII. Si necesita hacer esto con caracteres fuera del rango ASCII, use el modificador ''/ u'' para preg_match
y use mb_strtolower
.
Es fácil usar las clases de filtro de 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;
}
}
----- underscoreToCamelCase -----
simple_test >>> SimpleTest
fácil >>> fácil
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
fácil >>> fácil
HTML >>> html
simpleXML >>> simple_xml
PDFLoad >>> pdf_load
startMIDDLELast >>> start_middle_last
AString >>> a_string
Some4Numbers234 >>> some4_numbers234
TEST123String >>> test123_string
Eso es lo que uso para la decamelización de métodos:
function decamelize($str, $glue=''_'') {
$capitals = array();
$replace = array();
foreach(str_split($str) as $index => $char) {
if(ord($char) >= 65 && ord($char) <= 90) {
$capitals[] = $char;
$replace[] = ($index > 0 ? $glue : '''').strtolower($char);
}
}
if(sizeof($capitals)) return str_replace($capitals, $replace, $str);
return $str;
}
Hay una library proporciona esta funcionalidad:
SnakeCaseFormatter::run(''CamelCase''); // Output: "camel_case"
La biblioteca de código abierto TurboCommons contiene un método de propósito general formatCase () dentro de la clase StringUtils, que le permite convertir una cadena a muchos formatos de casos comunes, como CamelCase, UpperCamelCase, LowerCamelCase, snake_case, Title Case y muchos más.
https://github.com/edertone/TurboCommons
Para usarlo, importe el archivo phar a su proyecto y:
use org/turbocommons/src/main/php/utils/StringUtils;
echo StringUtils::formatCase(''camelCase'', StringUtils::FORMAT_SNAKE_CASE);
// will output ''camel_Case''
La mayoría de las soluciones aquí se sienten pesadas. Esto es lo que uso:
$underscored = strtolower(
preg_replace(
["/([A-Z]+)/", "/_([A-Z]+)([A-Z][a-z])/"],
["_$1", "_$1_$2"],
lcfirst($camelCase)
)
);
"CamelCASE" se convierte en "camel_case"
-
lcfirst($camelCase)
bajará el primer carácter (evita que la salida convertida ''CamelCASE'' comience con un guión bajo) -
[AZ]
encuentra letras mayúsculas -
+
tratará cada mayúscula consecutiva como una palabra (evita que CamelCASE se convierta en camel_C_A_S_E) - El segundo patrón y el reemplazo corresponden a
ThoseSPECCases
->those_spec_cases
lugar dethose_speccases
-
strtolower([…])
convierte la salida en minúsculas
La peor respuesta aquí estuvo tan cerca de ser la mejor (usar un marco). NO, NO, solo eche un vistazo al código fuente. ver lo que un marco bien establecido usa sería un enfoque mucho más confiable (probado y probado). El marco de Zend tiene algunos filtros de palabras que se ajustan a sus necesidades. Source
aquí hay un par de métodos que adapté de la fuente.
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");
No es nada sofisticado sino simple y rápido como el infierno:
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
Portado de Ruby''s String#camelize
y 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);
}
Un truco que las soluciones anteriores pueden haber pasado por alto es el modificador ''e'' que hace que preg_replace
evalúe la cadena de reemplazo como código PHP.
Prueba esto para el tamaño:
$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);
}
Salida:
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
Esto implementa las siguientes reglas:
- Una secuencia que comienza con una letra minúscula debe ir seguida de letras minúsculas y dígitos;
- Una secuencia que comienza con una letra mayúscula puede ir seguida de:
- una o más letras mayúsculas y dígitos (seguidos por el final de la cadena o una letra mayúscula seguida de una letra o dígito minúsculo, es decir, el inicio de la siguiente secuencia); o
- una o más letras minúsculas o dígitos.
SI pudieras comenzar con:
$string = ''Camel_Case''; // underscore or any other separator...
Entonces podrías convertir cualquier caso solo con:
$pascal = str_replace("_", "", $string);
$snake = strtolower($string);
O en cualquier otro caso:
$capitalized = str_replace("_", " ", $string); // Camel Case
$constant = strtoupper($string); // CAMEL_CASE
$train = str_replace("_", "-", $snake); // camel-case
Si está buscando una versión de PHP 5.4 y una respuesta posterior, aquí está el código:
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
);
}
Si usa la plataforma Laravel, puede usar el método snake_case() .
Una solución concisa y puede manejar algunos casos de uso difíciles:
function decamelize($string) {
return strtolower(preg_replace([''/([a-z/d])([A-Z])/'', ''/([^_])([A-Z][a-z])/''], ''$1_$2'', $string));
}
Puede manejar todos estos casos:
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
Puede probar esta función aquí: http://syframework.alwaysdata.net/decamelize
Una solución más corta: similar a la del editor con una expresión regular simplificada y solucionando el problema del "subrayado final":
$output = strtolower(preg_replace(''/(?<!^)[A-Z]/'', ''_$0'', $input));
Demo de PHP | Demostración de Regex
Tenga en cuenta que casos como SimpleXML
se convertirán en simple_x_m_l
usando la solución anterior. También se puede considerar un uso incorrecto de la notación de mayúsculas y minúsculas (correcto sería SimpleXml
) en lugar de un error del algoritmo, ya que tales casos son siempre ambiguos: incluso agrupando caracteres en mayúsculas en una cadena ( simple_xml
) dicho algoritmo siempre fallará en otros casos XMLHTMLConverter
como XMLHTMLConverter
o palabras de una sola letra cerca de abreviaturas, etc. Si no te XMLHTMLConverter
casos XMLHTMLConverter
(bastante raros) y quieres manejar SimpleXML
correctamente, puedes utilizar una solución un poco más compleja:
$output = ltrim(strtolower(preg_replace(''/[A-Z]([A-Z](?![a-z]))*/'', ''_$0'', $input)), ''_'');
Una versión que no usa expresiones regulares se puede encontrar en la fuente de 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);
}
php no ofrece una función integrada para este afaik, pero esto es lo que uso
function uncamelize($camel,$splitter="_") {
$camel=preg_replace(''/(?!^)[[:upper:]][[:lower:]]/'', ''$0'', preg_replace(''/(?!^)[[:upper:]]+/'', $splitter.''$0'', $camel));
return strtolower($camel);
}
el divisor se puede especificar en la llamada a la función, por lo que puede llamarlo así
$camelized="thisStringIsCamelized";
echo uncamelize($camelized,"_");
//echoes "this_string_is_camelized"
echo uncamelize($camelized,"-");
//echoes "this-string-is-camelized"
danielstjules/Stringy proporciona un método para convertir cuerdas de camelcase a snakecase.
s(''TestUCase'')->underscored(); // ''test_u_case''
$str = ''FooBarBaz'';
return strtolower(preg_replace(''~(?<=//w)([A-Z])~'', ''_$1'', $str)); // foo_bar_baz
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);
}
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_áááá_őőőő
(La "solución" aceptada es una falla épica ...)