Jak przekonwertować PascalCase na pascal_case?


Odpowiedzi:


163

Wypróbuj ten rozmiar:

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

Wynik:

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

To implementuje następujące zasady:

  1. Po sekwencji zaczynającej się od małej litery muszą następować małe litery i cyfry;
  2. Po sekwencji zaczynającej się od dużej litery może następować:
    • jedna lub więcej wielkich liter i cyfr (po których następuje koniec ciągu lub wielka litera, po której następuje mała litera lub cyfra, czyli początek następnej sekwencji); lub
    • jedna lub więcej małych liter lub cyfr.

9
Działa dla łańcuchów CamelCased (zgodnie z pytaniem openfrog), ale jeśli użyjesz go z ciągiem wejściowym, na przykład „r_id” (już „podkreślono”), przycina prefiks („r_”). Dobre rozwiązanie, ale zdecydowanie nie uniwersalne.
Martin

1
Ciekawe, dlaczego sprawdzasz, czy ciąg pasuje do ciągu z wielkimi literami? Jaka jest korzyść z zamiany tylko pierwszego znaku na małe litery (w przeciwieństwie do wszystkich znaków)?
Josh

1
Bardziej zwięzłe rozwiązanie, które może również obsługiwać wszystkie te przypadki użycia: stackoverflow.com/a/35719689/4328383
Syone

156

Krótsze rozwiązanie: podobne do edytora z uproszczonym wyrażeniem regularnym i naprawiającym problem „końcowego podkreślenia”:

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

Demo PHP | Regex Demo


Zwróć uwagę, że przypadki takie jak SimpleXMLzostaną przekonwertowane na simple_x_m_lprzy użyciu powyższego rozwiązania. Można to również uznać za niewłaściwe użycie notacji wielkości liter wielbłąda (poprawne byłoby SimpleXml) zamiast błędu algorytmu, ponieważ takie przypadki są zawsze niejednoznaczne - nawet poprzez zgrupowanie wielkich liter w jeden ciąg ( simple_xml) taki algorytm zawsze zawiedzie w innych przypadkach skrajnych podobne XMLHTMLConverterlub jednoliterowe słowa w pobliżu skrótów itp. Jeśli nie masz nic przeciwko (raczej rzadkim) skrajnym przypadkom i chcesz SimpleXMLpoprawnie obsłużyć , możesz użyć nieco bardziej złożonego rozwiązania:

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

Demo PHP | Regex Demo


Nie wahaj się skomentować odpowiedzi Cletusa, wyszczególniając, które przypadki testowe zostały naprawione.
Mike B

3
Nie twierdzę, że jego rozwiązanie daje złe wyniki. Jego rozwiązanie jest po prostu niezwykle skomplikowane i nieskuteczne.
Jan Jakeš

1
Tak, akceptacja odpowiedzi jest zdecydowanie porażką. Rozwiązanie Jana jest niesamowite! Na marginesie, myślę, że to (lub niewielka zmiana) jest moim nowym, ulubionym testem kodowania dla programistów PHP, ponieważ liczba odpowiedzi udzielonych na to pytanie, które w rzeczywistości nie działają, jest niesamowita. Byłby to świetny sposób na wstępne filtrowanie. :-)
JamesG

stwierdził, że wyrażenie regularne użyte w tym rozwiązaniu jest znacznie bardziej kompletne: stackoverflow.com/questions/2559759/ ...
thoroc

2
Dobre rozwiązanie dla prostych przypadków użycia iw większości zwykłych przypadków wystarczy, ale zaakceptowane rozwiązanie może obsłużyć więcej przypadków użycia, na przykład „simpleXML” może zostać przekonwertowane na „simple_xml”, a nie „simple_x_m_l”
Syone

35

Zwięzłe rozwiązanie i poradzi sobie z trudnymi przypadkami użycia:

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

Może obsłużyć wszystkie te przypadki:

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

Możesz przetestować tę funkcję tutaj: http://syframework.alwaysdata.net/decamelize


@VivekVardhan, której części tego wyrażenia regularnego nie rozumiesz?
Syone

Uhm, myślę, że małe litery nie są literami wielbłąda jest efektem ubocznym, w przypadku, gdy ciąg nie jest w formacie wielbłąda, należy zwrócić oryginalny. Rzeczywiście, jeśli wyślesz „simple_Text”, otrzymasz Fail: simple_Test => simple_Test [simple_test]. Małe litery powinny być wykonane tylko i jeśli tylko oryginalny ciąg jest prawdziwym łańcuchem wielbłądów. Co myślisz o?
guido

24

Przeniesione z Ruby's String#camelizei 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); 
}

Jedną ze sztuczek, które mogły zostać pominięte w powyższych rozwiązaniach, jest modyfikator „e”, który powoduje preg_replaceobliczenie zastępczego ciągu znaków jako kodu PHP.


10
eFlag na preg_replacejest przestarzałe w PHP 5.5.
cdmckay

A tak przy okazji, nie ma ich też w Rubim, ale w bibliotece inflatora Railsów - kamelizuj i podkreślaj. api.rubyonrails.org/classes/ActiveSupport/Inflector.html
mahemoff

2
To się nie powiedzie w przypadku „ThisIsATest”. Wydaje się, że nie obsługuje dwóch kolejnych wielkich liter.
OnaBai,

Uwaga: możesz użyć lcfirst, aby zmienić pierwszą literę na małą, wtedy nie potrzebujesz ^|ani strlen.
Benubird


23

Symfony serializer Komponent ma CamelCaseToSnakeCaseNameConverter że ma dwie metody normalize()i denormalize(). Można ich używać w następujący sposób:

$nameConverter = new CamelCaseToSnakeCaseNameConverter();

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

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

1
Strzec się! $nameConverter->normalize('CamelCase')wyjścia _camel_casew aktualnej wersji 3.2 komponentu Symfony Serializer.
spackmat

21

Większość rozwiązań jest tutaj ciężka. Oto czego używam:

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

„CamelCASE” jest konwertowany na „camel_case”

  • lcfirst($camelCase) obniży pierwszy znak (pozwala uniknąć konwersji danych wyjściowych „CamelCASE” na początek podkreślenia)
  • [A-Z] znajduje wielkie litery
  • + potraktuje każdą kolejną wielką literę jako słowo (unika konwersji „CamelCASE” na camel_C_A_S_E)
  • Drugi wzór i zamiana są dla ThoseSPECCases-> those_spec_caseszamiastthose_speccases
  • strtolower([…]) zamienia dane wyjściowe na małe litery

3
Ale zmienia też CamelCased na _camel_cased.
acme

1
to jest świetne - po prostu dodaj podciąg zaczynający się od znaku 1, aby obejść ten problem.
Oddman

4
Doskonale! Wystarczy dodać lcfirstfunkcję do $ camelCase
Edakos,

Zaakceptowana odpowiedź będzie obsługiwać: TestUPSClass w test_ups_class, podczas gdy to zmieni ją w test_u_p_s_class, o czym należy pamiętać.
Mazzy

Ciąg wejściowy, który zaczyna się od pierwszego „słowa” z allcaps, zostanie nieoczekiwanie podzielony przez to rozwiązanie z powodu ucfirst()wywołania. USADollarSymbolstaje się u_sa_dollar_symbol Demo Nie polecam tego rozwiązania, ponieważ musi wykonać dwa przejścia przez ciąg wejściowy z wyrażeniem regularnym - znakiem nierafinowanego wzorca.
mickmackusa

19

php nie oferuje wbudowanej funkcji dla tego afaika, ale oto czego używam

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

}

rozdzielacz można określić w wywołaniu funkcji, więc możesz go wywołać w ten sposób

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

2
To się nie powiedzie w przypadku „ThisIsATest”. Wydaje się, że nie obsługuje dwóch kolejnych wielkich liter.
OnaBai

Na pewno o czymś zapomniałeś, bo druga wymiana nic nie robi. Oprócz tego możesz łatwo dostosować go do Unicode mb_strtoloweri włączyć /uopcję preg_replace.
bodo

8

Musisz przepuścić przez to wyrażenie regularne, które pasuje do każdej dużej litery, z wyjątkiem sytuacji, gdy jest na początku, i zastąpić je podkreśleniem i tą literą. Oto rozwiązanie UTF-8:

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

Jeśli nie jesteś pewien, jaką wielkością jest Twój ciąg, lepiej najpierw go sprawdzić, ponieważ ten kod zakłada, że ​​dane wejściowe to camelCasezamiast underscore_Caselubdash-Case , więc jeśli ostatnie litery mają duże litery, doda do nich podkreślenia.

Przyjęta odpowiedź od cletus jest zbyt skomplikowana i działa tylko w przypadku znaków łacińskich. Uważam, że to naprawdę złe rozwiązanie i zastanawiam się, dlaczego w ogóle zostało zaakceptowane. Konwersja TEST123Stringna test123_stringniekoniecznie jest ważnym wymaganiem. Utrzymałem to raczej w prostocie i rozdzieleniu ABCcccna a_b_cccczamiast, ab_ccccponieważ nie traci w ten sposób informacji, a konwersja wsteczna da dokładnie ten sam ciąg, od którego zaczęliśmy. Nawet jeśli chcesz to zrobić w inny sposób, stosunkowo łatwo jest napisać dla niego wyrażenie regularne z dodatnim lookbehind (?<!^)\p{Lu}\p{Ll}|(?<=\p{Ll})\p{Lu}lub dwoma wyrażeniami regularnymi bez lookbehind, jeśli nie jesteś ekspertem od wyrażeń regularnych. Nie ma potrzeby dzielenia go na podciągi, nie wspominając o decydowaniu, gdzie strtoloweri lcfirstgdzie użycie strtolowerbyłoby całkowicie w porządku.


Odpowiedzi zawierające tylko kod mają niską wartość w Stackoverflow, ponieważ niewiele robią, aby edukować / wspierać tysiące przyszłych badaczy.
mickmackusa

@mickmackusa Jeśli naukowcy nauczą się kodować z SO, to mamy poważny problem ...
inf3rno

Teraz, gdy masz już ten osobisty atak z systemu, popraw odpowiedź. Zakładając, że wiesz, jak działa Twoje rozwiązanie i dlaczego używasz tych modyfikatorów wzorców, nie widzę powodu, aby odmawiać tej społeczności wiedzy. Jeśli rozważasz pozostawienie bardziej złośliwych odpowiedzi, zapewniam cię, że nie przeszkadzają mi. W czasie, gdy zajmowałeś się komentowaniem, mogłeś uzupełnić swoją odpowiedź, mogliśmy usunąć nasze komentarze, a ja mogłem pójść gdzie indziej, aby pomóc tej witrynie.
mickmackusa

Oczywiście nie mam uprawnień do usuwania postów z 8 głosami za. Jeśli chcesz, możesz usunąć swoją odpowiedź, ale nie byłoby trudno po prostu ją poprawić, usuwając niepotrzebne modyfikatory wzorców i dodając wyjaśnienie. Osobiste ataki nie mają na mnie żadnego wpływu.
mickmackusa

@mickmackusa Nie sądzę, żebym też mógł go usunąć. Jeśli chcesz, możesz go edytować.
inf3rno

6

Jeśli szukasz wersji PHP 5.4 i późniejszej odpowiedzi, oto kod:

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 produkuje "SmsSent" dla sms_sent, potrzebujesz lcfirst
mik3fly-4steri5k

4

Wcale nie wyszukane, ale proste i szybkie jak diabli:

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

++$izamiast $i++to trochę przyspieszyć;)
Mathieu Amiot

Odpowiedzi zawierające tylko kod mają niską wartość w Stackoverflow, ponieważ niewiele robią, aby edukować / wspierać tysiące przyszłych badaczy.
mickmackusa

4

„CamelCase” na „camel_case”:

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

lub:

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

Dziękuję Ci. Użyłem pierwszego podejścia, ale z myślnikami do wygenerowaniathis-kind-of-output
thexpand

3

Wersję, która nie używa wyrażenia regularnego, można znaleźć w źródle 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
Tak wyglądałoby życie bez wyrażenia regularnego :-)
ekhaled

4
Heh, tak. RegEx z pewnością ma swoje zalety. :) Surowa prędkość nie jest jedną z nich.
Darrell Brogdon,

z jakiegoś powodu uzyskałem zabawne wyniki
mr1031011

Nie działa dla mnie na podstawie tego ciągu: "CamelCaseTestAAATestAA", powinien mieć: "camel_case_test_a_a_a_test_a_a", ma: "" camel_case_test_aest "...
Sybio

3

Więc tutaj jest jedna linijka:

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

Fajnie, ale konwertuje tylko pierwszy wygląd, więc polecam dodanie gmodyfikatora do tego wyrażenia regularnego.
acme

@acme, używam go bez gi działa dobrze dla mnie.
widzi

Z jakiegoś powodu w moim przypadku musiałem dodać rozszerzenie g. Ale nie pamiętam frazy, z którą testowałem.
acme


3

Laravel 5.6 zapewnia bardzo prosty sposób na zrobienie tego:

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

Co robi: jeśli widzi, że w danym ciągu znajduje się co najmniej jedna duża litera, używa dodatniego lookahead, aby wyszukać dowolny znak ( .), po którym następuje duża litera ( (?=[A-Z])). Następnie zastępuje znaleziony znak jego wartością, po której następuje separator _.


Ta funkcja wydaje się teraz nazywać snake_case () i żyje w globalnej przestrzeni nazw.
Wotuu

2

Bezpośrednim portem z railsów (bez ich specjalnej obsługi dla :: lub akronimów) byłoby

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

Znając PHP, będzie to szybsze niż ręczne analizowanie, które ma miejsce w innych odpowiedziach podanych tutaj. Wadą jest to, że nie możesz wybrać, czego użyć jako separatora między słowami, ale nie było to częścią pytania.

Sprawdź również kod źródłowy odpowiednich railsów

Należy pamiętać, że jest to przeznaczone do użytku z identyfikatorami ASCII. Jeśli musisz to zrobić ze znakami spoza zakresu ASCII, użyj modyfikatora „/ u” preg_matchi użyj mb_strtolower.


Możesz, jeśli po prostu dodasz parametr zawierający żądany znak.
Fleshgrinder

2

Oto mój wkład w pytanie od sześciu lat, w którym Bóg wie, ile odpowiedzi ...

Konwertuje wszystkie słowa w podanym ciągu, które są w postaci wielbłąda, na futerał węża. Na przykład „SuperSpecialAwesome, a także FizBuzz καιΚάτιΑκόμα” zostaną przekonwertowane na „super_special_awesome, a także fizz_buzz και_κάτι_ακόμα”.

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

2

Yii2 ma inną funkcję, aby utworzyć słowo snake_case z 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

Krótkie rozwiązanie:

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

2

Miałem podobny problem, ale nie mogłem znaleźć żadnej odpowiedzi, która byłaby satysfakcjonująca, jak przekonwertować CamelCase na snake_case, unikając zduplikowanych lub zbędnych podkreśleń _ dla nazw z podkreśleniami lub wszystkimi skrótami .

Problem jest następujący:

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

Rozwiązanie, które napisałem, to proste wywołanie dwóch funkcji, małe litery i wyszukiwanie oraz zamiana na kolejne małe i duże litery:

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

Jak dotąd jest to najbardziej zwięzłe i przydatne rozwiązanie 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);
}

Możesz uzyskać dostęp do znaków bezpośrednio za pomocą $name{$k}(lub $name[$k]), co wydłużyłoby twój kod, ale pozwala uniknąć dużego narzutu konwersji do iz tablicy.
bodo

Odpowiedzi zawierające tylko kod mają niską wartość w StackOverflow, ponieważ słabo wzmacniają / kształcą przyszłych badaczy. Twoje rozwiązanie, unikając łaski wyrażenia regularnego, jest bardzo uciążliwe i zawiłe. Dzielisz każdy znak i wykonujesz wiele iteracyjnych wywołań funkcji. Wyznaczanie pustego sznurka jako kleju nie jest konieczne. Nie zajmowałbym się tym rozwiązaniem w jednym ze swoich projektów, ponieważ nie ma tu elegancji, niskiej czytelności i n liczby niepotrzebnych wywołań funkcji.
mickmackusa

1

Najgorsza odpowiedź była tak bliska bycia najlepszą (użyj frameworka). NIE NIE, po prostu spójrz na kod źródłowy. zobaczenie, jakie zastosowania mają dobrze ugruntowane ramy, byłoby znacznie bardziej niezawodnym podejściem (wypróbowanym i przetestowanym). Framework Zend ma kilka filtrów słów, które odpowiadają Twoim potrzebom. Źródło .

oto kilka metod, które zaadaptowałem ze źródła.

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

Istnieje biblioteka zapewniająca taką funkcjonalność:

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

1
Myślę, że masz na myśli „Stworzyłem bibliotekę zapewniającą taką funkcjonalność”. Nie ma nic złego w autopromocji, ale nie ukrywaj tego.
icc97


1

To jeden z krótszych sposobów:

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

Odpowiedzi zawierające tylko kod mają niską wartość w Stackoverflow, ponieważ niewiele robią, aby edukować / wspierać tysiące przyszłych badaczy.
mickmackusa

1
@mickmackusa - tysiące przyszłych badaczy będzie zainteresowanych elegancką, jednokierunkową wersją i będzie się uczyć.
Teson

Przykro mi, że przyjąłeś tę samolubną postawę. Z pewnością mogłeś dodać wyjaśnienie w czasie, jaki zajęło ci zaprojektowanie i wpisanie tej złośliwej odpowiedzi. Twoja odpowiedź powoduje trzy wywołania funkcji, ale inne wykonują zadanie w dwóch.
mickmackusa

1

Jak usunąć kamelizację bez użycia wyrażenia regularnego:

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

Edycja:

Jak bym to zrobił w 2019 roku:

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

A kiedy pojawi się PHP 7.4:

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

1
Odpowiedzi zawierające tylko kod mają niską wartość w StackOverflow, ponieważ słabo wzmacniają / kształcą przyszłych badaczy. Wykonywanie od 1 do 3 wywołań funkcji dla każdego znaku w ciągu, a następnie dwóch kolejnych wywołań funkcji po zakończeniu pętli jest bardzo trudne. Nie znalazłbym rozwiązania przy tak słabej ekonomii.
mickmackusa

To przykład, jak można to zrobić bez użycia wyrażeń regularnych, a nie jak powinno być używane w produkcji, więc nie widzę twojego punktu poza tym, że narzekasz na odpowiedź 5lat / o, która ma jeden głos za i jest mało prawdopodobne, aby została zauważona przez żadnych badaczy.
baldrs

Zwracam uwagę na wszystkie posty, nie tylko te wysoko oceniane lub ostatnio. Nie narzekam, przedstawiam swoją krytykę, aby badacze z mniejszą wiedzą mogli lepiej zrozumieć różnicę między tą odpowiedzią a innymi odpowiedziami. Mogłeś wyjaśnić w swoim poście, że unikanie wyrażeń regularnych było jedynie akademickim wyzwaniem. To powiedziawszy, istnieją sposoby na zwiększenie wydajności tego procesu dzięki lepszym praktykom kodowania.
mickmackusa

0

Korzystanie z klas filtrów w Zend Word Filters jest łatwe :

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

----- podkreślenieToCamelCase -----

simple_test >>> SimpleTest

łatwe >>> łatwe

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

łatwe >>> łatwe

HTML >>> html

simpleXML >>> simple_xml

PDFLoad >>> pdf_load

startMIDDLELast >>> start_middle_last

AString >>> a_string

Some4Numbers234 >>> some4_numbers234

TEST123String >>> test123_string


0

Biblioteka TurboCommons typu open source zawiera metodę formatCase () ogólnego przeznaczenia w klasie StringUtils, która umożliwia konwersję ciągu znaków na wiele popularnych formatów liter, takich jak CamelCase, UpperCamelCase, LowerCamelCase, snake_case, Title Case i wiele innych.

https://github.com/edertone/TurboCommons

Aby z niego skorzystać, zaimportuj plik phar do swojego projektu i:

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
Odpowiedzi zawierające tylko kod mają niską wartość w StackOverflow, ponieważ słabo wzmacniają / kształcą przyszłych badaczy.
mickmackusa

-1

JEŚLI mógłbyś zacząć od:

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

Następnie możesz przekonwertować na dowolny przypadek tylko za pomocą:

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

Lub w innych przypadkach:

$capitalized = str_replace("_", " ", $string); // Camel Case
$constant = strtoupper($string);               // CAMEL_CASE
$train = str_replace("_", "-", $snake);        // camel-case
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.