Come convertire PascalCase in pascal_case?


Risposte:


163

Prova questo per le dimensioni:

$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);
}

Produzione:

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

Questo implementa le seguenti regole:

  1. Una sequenza che inizia con una lettera minuscola deve essere seguita da lettere minuscole e cifre;
  2. Una sequenza che inizia con una lettera maiuscola può essere seguita da:
    • una o più lettere e cifre maiuscole (seguite dalla fine della stringa o da una lettera maiuscola seguita da una lettera o cifra minuscola, ovvero l'inizio della sequenza successiva); o
    • una o più lettere o cifre minuscole.

9
Funziona per le stringhe CamelCased (come richiesto da openfrog), ma se lo usi con la stringa di input per esempio "r_id" (già "underscored") taglia il prefisso ("r_"). Buona soluzione, ma decisamente non universale.
Martin,

1
Sei curioso di controllare se la stringa corrisponde a una stringa con tutte le maiuscole? Qual è il vantaggio di convertire solo il primo carattere in minuscolo (al contrario di tutti i caratteri)?
Josh,

1
Una soluzione più conciso che può anche gestire tutti questi casi di utilizzo: stackoverflow.com/a/35719689/4328383
Syone

156

Una soluzione più breve: simile a quella dell'editor con un'espressione regolare semplificata e che risolve il problema "trailing-underscore":

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

Demo PHP | Demo Regex


Nota che casi come SimpleXMLverranno convertiti simple_x_m_lutilizzando la soluzione di cui sopra. Questo può anche essere considerato un uso errato della notazione delle maiuscole (sarebbe corretto SimpleXml) piuttosto che un bug dell'algoritmo poiché tali casi sono sempre ambigui - anche raggruppando caratteri maiuscoli in una stringa ( simple_xml) tale algoritmo fallirà sempre in altri casi limite XMLHTMLConverterparole simili o di una lettera accanto alle abbreviazioni, ecc. Se non ti interessano i casi limite (piuttosto rari) e desideri gestirli SimpleXMLcorrettamente, puoi utilizzare una soluzione un po 'più complessa:

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

Demo PHP | Demo Regex


Sentiti libero di commentare la risposta di cletus in dettaglio quali casi di test hai corretto.
Mike B

3
Non sto dicendo che la sua soluzione dia risultati sbagliati. La sua soluzione è semplicemente estremamente complicata e inefficace.
Jan Jakeš

1
Sì, la risposta accettata è sicuramente un fallimento. La soluzione di Jan è fantastica! Come nota a margine, penso che questo (o una leggera variazione) sia il mio nuovo test di codifica preferito per gli sviluppatori PHP, perché il numero di risposte fornite a questa domanda che in realtà non funzionano è incredibile. Sarebbe un ottimo modo per eseguire il filtraggio iniziale. :-)
JamesG

trovato l'espressione regolare utilizzata in questa soluzione molto più completo: stackoverflow.com/questions/2559759/...
thoroc

2
Bella soluzione per casi d'uso semplici e nella maggior parte dei casi comuni è sufficiente ma la soluzione accettata può gestire più casi d'uso, ad esempio "simpleXML" può essere convertito in "simple_xml" e non "simple_x_m_l"
Syone

35

Una soluzione concisa e in grado di gestire alcuni casi d'uso complicati:

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

Può gestire tutti questi casi:

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

Puoi testare questa funzione qui: http://syframework.alwaysdata.net/decamelize


@VivekVardhan quale parte di questa regex non capisci?
Syone

Uhm, penso che le stringhe minuscole non camelcase siano un effetto collaterale, nel caso in cui la stringa non sia nel formato camel case dovrebbe essere restituita quella originale. Infatti se invii 'simple_Text' ottieni Fallimento: simple_Test => simple_Test [simple_test]. La stringa minuscola dovrebbe essere fatta solo e solo se la stringa originale è una vera stringa di cammello. Che cosa ne pensi?
guido

24

Portato da Ruby String#camelizee 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 trucco che le soluzioni precedenti potrebbero aver perso è il modificatore "e" che fa preg_replacevalutare la stringa di sostituzione come codice PHP.


10
Il eflag per preg_replaceè stato deprecato in PHP 5.5.
cdmckay

A proposito, anche questi non sono in Ruby, ma nella libreria di inflector di Rails: camelize e underscore. api.rubyonrails.org/classes/ActiveSupport/Inflector.html
mahemoff

2
Questo non riesce per "ThisIsATest". Sembra che non supporti due maiuscole consecutive.
OnaBai

Solo una nota: puoi usare lcfirst per ottenere la prima lettera in minuscolo, quindi non hai bisogno di ^|o strlen.
Benubird


23

Il componente Serializer di Symfony ha un CamelCaseToSnakeCaseNameConverter che ha due metodi normalize()e denormalize(). Questi possono essere usati come segue:

$nameConverter = new CamelCaseToSnakeCaseNameConverter();

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

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

1
Attenzione! $nameConverter->normalize('CamelCase')output _camel_casenella versione corrente 3.2 del componente Serializer di Symfony.
spackmat

21

La maggior parte delle soluzioni qui sembra pesante. Ecco cosa utilizzo:

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

"CamelCASE" viene convertito in "camel_case"

  • lcfirst($camelCase) abbasserà il primo carattere (evita che l'output convertito di 'CamelCASE' inizi con un trattino basso)
  • [A-Z] trova le lettere maiuscole
  • + tratterà ogni maiuscolo consecutivo come una parola (evita che "CamelCASE" venga convertito in camel_C_A_S_E)
  • Il secondo modello e la sostituzione sono per ThoseSPECCases-> those_spec_casesinvece dithose_speccases
  • strtolower([…]) trasforma l'output in minuscolo

3
Ma trasforma anche CamelCased in _camel_cased.
acme

1
questo è fantastico: basta aggiungere un substr a partire da char 1 per aggirare il problema.
Oddman

4
Eccellente! Ho solo bisogno di aggiungere una lcfirstfunzione a $ camelCase
Edakos

La risposta accettata gestirà: TestUPSClass in test_ups_class mentre questo lo trasformerà in test_u_p_s_class, qualcosa da tenere a mente.
Mazzy

Una stringa di input che inizia con una prima "parola" allcaps verrà divisa inaspettatamente da questa soluzione a causa della ucfirst()chiamata. USADollarSymboldiventa u_sa_dollar_symbol Demo Non consiglio questa soluzione perché deve fare due passaggi attraverso la stringa di input con regex - segno di un pattern non raffinato.
mickmackusa

19

php non offre una funzione integrata per questo afaik, ma ecco cosa uso

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

}

lo splitter può essere specificato nella chiamata di funzione, quindi puoi chiamarlo in questo modo

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

2
Questo non riesce per "ThisIsATest". Sembra che non supporti due maiuscole consecutive.
OnaBai

Sicuramente hai dimenticato qualcosa perché la seconda sostituzione non fa nulla. Oltre a questo, puoi facilmente renderlo compatibile con Unicode mb_strtolowere l' /uopzione su preg_replace.
bodo

8

È necessario eseguire un'espressione regolare attraverso di essa che corrisponda a ogni lettera maiuscola tranne se è all'inizio e sostituirla con un trattino basso più quella lettera. Una soluzione utf-8 è questa:

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_áááá_őőőő

Se non sei sicuro di quale sia il caso della tua stringa, è meglio controllarlo prima, perché questo codice presuppone che l'input sia camelCaseinvece di underscore_Caseo dash-Case, quindi se questi ultimi hanno lettere maiuscole, aggiungerà caratteri di sottolineatura.

La risposta accettata da cletus è troppo complicata imho e funziona solo con caratteri latini. La trovo davvero una pessima soluzione e mi chiedo perché sia ​​stata accettata. La conversione TEST123Stringin test123_stringnon è necessariamente un requisito valido. L'ho tenuto piuttosto semplice e separato ABCcccin a_b_ccccinvece di ab_ccccperché non perde le informazioni in questo modo e la conversione all'indietro darà la stessa identica stringa con cui abbiamo iniziato. Anche se vuoi farlo in un altro modo, è relativamente facile scrivere una regex con lookbehind positivo (?<!^)\p{Lu}\p{Ll}|(?<=\p{Ll})\p{Lu}o due regex senza lookbehind se non sei un esperto di regex. Non è necessario dividerlo in sottostringhe per non parlare di decidere tra strtolowere lcfirstdove usarlo strtolowerandrebbe benissimo.


Le risposte di solo codice hanno un valore basso su Stackoverflow perché fanno ben poco per istruire / potenziare migliaia di futuri ricercatori.
mickmackusa

@mickmackusa Se i ricercatori imparano a programmare da SO, allora abbiamo un problema serio ...
inf3rno

Ora che hai eliminato l'attacco personale dal tuo sistema, migliora la tua risposta. Supponendo che tu sappia come funziona la tua soluzione e perché stai usando quei modificatori di pattern, non vedo una buona ragione per negare la conoscenza a questa comunità. Se stai pensando di lasciare risposte più irriverenti, ti assicuro che non mi danno fastidio. Nel tempo che hai impiegato per commentare, avresti potuto completare la tua risposta, avremmo potuto cancellare i nostri commenti e io sarei potuto andare altrove per aiutare questo sito.
mickmackusa

Ovviamente non ho l'autorità per eliminare un post con 8 voti positivi. Se lo desideri, puoi eliminare la tua risposta, ma non sarebbe molto difficile migliorarla semplicemente rimuovendo i modificatori di pattern non necessari e aggiungendo una spiegazione. Gli attacchi personali non hanno effetto su di me.
mickmackusa

@mickmackusa Non credo di poterlo eliminare neanche io. Sentiti libero di modificarlo se lo desideri.
inf3rno

6

Se stai cercando una versione PHP 5.4 e una risposta successiva, ecco il codice:

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 produce "SmsSent" per sms_sent, hai bisogno di un lcfirst
mik3fly-4steri5k

4

Per niente elegante ma semplice e veloce da morire:

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

++$iinvece di $i++renderlo anche un po 'più veloce;)
Mathieu Amiot

Le risposte di solo codice hanno un valore basso su Stackoverflow perché fanno ben poco per istruire / potenziare migliaia di futuri ricercatori.
mickmackusa

4

Da "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, '_');
}

Grazie. Ho usato il primo approccio, ma con i trattini per generarethis-kind-of-output
espansione

3

Una versione che non usa regex può essere trovata nella fonte 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
Ecco come sarebbe la vita senza regex :-)
ekhaled

4
Eh, sì. RegEx ha sicuramente i suoi vantaggi. :) La velocità grezza non è una di queste.
Darrell Brogdon

ha ottenuto alcuni risultati divertenti con questo per qualche motivo
mr1031011

Non funziona per me in base a questa stringa: "CamelCaseTestAAATestAA", dovrebbe avere: "camel_case_test_a_a_a_test_a_a", ha: "" camel_case_test_aest "...
Sybio

3

Quindi ecco una battuta:

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

Bello, ma converte solo la prima apparizione, quindi consiglierei di aggiungere un gmodificatore a questa regex.
acme

@acme, lo uso senza ge funziona bene per me.
seelts

Per qualche motivo nel mio caso ho dovuto aggiungere il file g. Ma non ricordo la frase con cui ho provato.
acme

3

danielstjules / Stringy ha fornito un metodo per convertire le stringhe da camelcase a snakecase.

s('TestUCase')->underscored(); // 'test_u_case'

3

Laravel 5.6 fornisce un modo molto semplice per farlo:

 /**
 * 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;
}

Cosa fa: se vede che c'è almeno una lettera maiuscola nella stringa data, usa un lookahead positivo per cercare qualsiasi carattere ( .) seguito da una lettera maiuscola ( (?=[A-Z])). Quindi sostituisce il carattere trovato con il suo valore seguito dal separatore _.


Questa funzione ora sembra essere chiamata snake_case () e risiede nello spazio dei nomi globale.
Wotuu

2

La porta diretta da rails (meno la loro gestione speciale per :: o acronimi) sarebbe

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, '-', '_'));
}

Conoscendo PHP, questo sarà più veloce dell'analisi manuale che sta accadendo in altre risposte fornite qui. Lo svantaggio è che non puoi scegliere cosa usare come separatore tra le parole, ma questo non faceva parte della domanda.

Controlla anche il codice sorgente delle guide rilevanti

Notare che questo è inteso per l'uso con identificatori ASCII. Se è necessario eseguire questa operazione con caratteri al di fuori dell'intervallo ASCII, utilizzare il modificatore "/ u" per preg_matche utilizzare mb_strtolower.


Potresti, se aggiungi semplicemente un parametro che contiene il carattere desiderato.
Fleshgrinder

2

Ecco il mio contributo a una domanda di sei anni con dio sa quante risposte ...

Convertirà tutte le parole nella stringa fornita che si trovano in camelcase in snakecase. Ad esempio "SuperSpecialAwesome e anche FizBuzz καιΚάτιΑκόμα" verranno convertiti in "super_special_awesome e anche fizz_buzz και_κάτι_ακόμα".

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

2

Yii2 ha la diversa funzione di creare la parola snake_case da 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

Soluzione breve:

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

2

Ho avuto un problema simile ma non sono riuscito a trovare alcuna risposta che soddisfi come convertire CamelCase in snake_case, evitando caratteri di sottolineatura duplicati o ridondanti _per i nomi con trattini bassi o abbreviazioni tutte maiuscole.

Il problema è il seguente:

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

La soluzione che ho scritto è una semplice chiamata a due funzioni, minuscolo e cerca e sostituisci per lettere minuscole-maiuscole consecutive:

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

Di gran lunga questa è la soluzione più concisa e utile IMO.
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);
}

Puoi accedere ai caratteri direttamente usando $name{$k}(o $name[$k]), il che renderebbe il tuo codice più lungo, ma evita il grande sovraccarico di convertirlo in e da un array.
bodo

Le risposte di solo codice sono di scarso valore su StackOverflow perché fanno un cattivo lavoro di responsabilizzazione / educazione dei futuri ricercatori. La tua soluzione, pur evitando la grazia della regex, è molto pesante e contorta. Stai dividendo su ogni personaggio e facendo più chiamate di funzioni ripetute. Non è necessario nominare una stringa vuota come colla. Non prenderei in considerazione questa soluzione in uno dei miei progetti perché non c'è eleganza, bassa leggibilità e n numero di chiamate di funzione non necessarie.
mickmackusa

1

La risposta peggiore qui era così vicina all'essere la migliore (usa un framework). NO NON FARE, basta dare un'occhiata al codice sorgente. vedere cosa utilizza un framework ben consolidato sarebbe un approccio molto più affidabile (provato e testato). Il framework Zend ha alcuni filtri di parole che si adattano alle tue esigenze. Fonte .

ecco un paio di metodi che ho adattato dalla fonte.

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

C'è una libreria che fornisce questa funzionalità:

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

1
Penso che tu voglia dire "Ho creato una libreria che fornisce questa funzionalità". Niente di sbagliato nell'autopromozione, ma non nasconderlo.
icc97


1

Questo è uno dei modi più brevi:

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

Le risposte di solo codice hanno un valore basso su Stackoverflow perché fanno ben poco per istruire / potenziare migliaia di futuri ricercatori.
mickmackusa

1
@mickmackusa - migliaia di ricerche future saranno interessate a una battuta elegante e istruiranno se stessi.
Teson

Mi dispiace che tu abbia preso quella posizione egoista. Sicuramente avresti potuto aggiungere una spiegazione nel tempo che hai impiegato per progettare e digitare quella risposta sarcastica. La tua risposta effettua tre chiamate di funzione, ma altre eseguono l'attività in due.
mickmackusa

1

Come de-camelize senza usare 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;
}

Una modifica:

Come lo farei nel 2019:

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

E quando verrà rilasciato PHP 7.4:

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

1
Le risposte di solo codice sono di scarso valore su StackOverflow perché fanno un cattivo lavoro di responsabilizzazione / educazione dei futuri ricercatori. Effettuare da 1 a 3 chiamate di funzione su ogni carattere della stringa e poi altre due chiamate di funzione dopo che il ciclo è terminato è molto pesante. Non prenderei in considerazione una soluzione con un'economia così povera.
mickmackusa

È un esempio di come potrebbe essere fatto senza usare espressioni regolari, non come dovrebbe essere usato in produzione, quindi non vedo il tuo punto oltre al fatto che ti lamenti di una risposta di 5 anni che ha un voto positivo ed è improbabile che venga visto da eventuali ricercatori.
baldrs

Do la mia attenzione a tutti i post, non solo a quelli più votati o recenti. Non mi lamento, offro la mia critica in modo che i ricercatori con meno conoscenze possano capire meglio la differenza tra questa risposta e altre risposte. Avresti potuto spiegare nel tuo post che era solo una sfida accademica evitare regex. Detto questo, ci sono modi per rendere questo processo più efficiente con migliori pratiche di codifica.
mickmackusa

0

È facile usare le classi Filter dei filtri Zend Word :

<?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


0

La libreria TurboCommons open source contiene un metodo formatCase () generico all'interno della classe StringUtils, che consente di convertire una stringa in molti formati di maiuscole e minuscole comuni, come CamelCase, UpperCamelCase, LowerCamelCase, snake_case, Title Case e molti altri.

https://github.com/edertone/TurboCommons

Per usarlo, importa il file phar nel tuo progetto e:

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
Le risposte di solo codice sono di scarso valore su StackOverflow perché fanno un cattivo lavoro di responsabilizzazione / educazione dei futuri ricercatori.
mickmackusa

-1

SE potresti iniziare con:

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

Quindi puoi convertire in entrambi i casi solo con:

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

O qualsiasi altro caso:

$capitalized = str_replace("_", " ", $string); // Camel Case
$constant = strtoupper($string);               // CAMEL_CASE
$train = str_replace("_", "-", $snake);        // camel-case
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.