Jeśli miałbym:
$string = "PascalCase";
potrzebuję
"pascal_case"
Czy PHP oferuje funkcję do tego celu?
Jeśli miałbym:
$string = "PascalCase";
potrzebuję
"pascal_case"
Czy PHP oferuje funkcję do tego celu?
Odpowiedzi:
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:
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));
Zwróć uwagę, że przypadki takie jak SimpleXML
zostaną przekonwertowane na simple_x_m_l
przy 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 XMLHTMLConverter
lub jednoliterowe słowa w pobliżu skrótów itp. Jeśli nie masz nic przeciwko (raczej rzadkim) skrajnym przypadkom i chcesz SimpleXML
poprawnie 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)), '_');
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
Przeniesione z Ruby's String#camelize
i 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_replace
obliczenie zastępczego ciągu znaków jako kodu PHP.
e
Flag na preg_replace
jest przestarzałe w PHP 5.5.
^|
ani strlen
.
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
$nameConverter->normalize('CamelCase')
wyjścia _camel_case
w aktualnej wersji 3.2 komponentu Symfony Serializer.
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)ThoseSPECCases
-> those_spec_cases
zamiastthose_speccases
strtolower([…])
zamienia dane wyjściowe na małe literylcfirst
funkcję do $ camelCase
ucfirst()
wywołania. USADollarSymbol
staje 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.
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"
mb_strtolower
i włączyć /u
opcję preg_replace
.
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 camelCase
zamiast underscore_Case
lubdash-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 TEST123String
na test123_string
niekoniecznie jest ważnym wymaganiem. Utrzymałem to raczej w prostocie i rozdzieleniu ABCccc
na a_b_cccc
zamiast, ab_cccc
ponieważ 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 strtolower
i lcfirst
gdzie użycie strtolower
byłoby całkowicie w porządku.
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
);
}
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
++$i
zamiast $i++
to trochę przyspieszyć;)
„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, '_');
}
this-kind-of-output
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);
}
Więc tutaj jest jedna linijka:
strtolower(preg_replace('/(?|([a-z\d])([A-Z])|([^\^])([A-Z][a-z]))/', '$1_$2', $string));
g
modyfikatora do tego wyrażenia regularnego.
g
i działa dobrze dla mnie.
g
. Ale nie pamiętam frazy, z którą testowałem.
danielstjules / Stringy zapewnił metodę konwersji łańcucha znaków z wielbłąda na futerał węża.
s('TestUCase')->underscored(); // 'test_u_case'
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 _
.
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_match
i użyj mb_strtolower
.
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'
)
);
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));
}
Krótkie rozwiązanie:
$subject = "PascalCase";
echo strtolower(preg_replace('/\B([A-Z])/', '_$1', $subject));
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));
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);
}
$name{$k}
(lub $name[$k]
), co wydłużyłoby twój kod, ale pozwala uniknąć dużego narzutu konwersji do iz tablicy.
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");
Istnieje biblioteka zapewniająca taką funkcjonalność:
SnakeCaseFormatter::run('CamelCase'); // Output: "camel_case"
Jeśli używasz frameworka Laravel, możesz użyć po prostu metody snake_case () .
To jeden z krótszych sposobów:
function camel_to_snake($input)
{
return strtolower(ltrim(preg_replace('/([A-Z])/', '_\\1', $input), '_'));
}
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);
}
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
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'
$str = 'FooBarBaz';
return strtolower(preg_replace('~(?<=\\w)([A-Z])~', '_$1', $str)); // foo_bar_baz
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