Bagaimana cara mengubah PascalCase ke pascal_case?

115

Jika saya memiliki:

$string = "PascalCase";

saya butuh

"pascal_case"

Apakah PHP menawarkan fungsi untuk tujuan ini?

katak terbuka
sumber
31
Secara teknis, contoh string pertama adalah PascalCase.
Robin van Baalen
33
Dan contoh string kedua dikenal sebagai snake_case .
Pang

Jawaban:

163

Coba ini untuk ukuran:

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

Keluaran:

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

Ini menerapkan aturan berikut:

  1. Urutan yang dimulai dengan huruf kecil harus diikuti oleh huruf kecil dan angka;
  2. Urutan yang dimulai dengan huruf besar dapat diikuti oleh:
    • satu atau lebih huruf besar dan angka (diikuti dengan ujung string atau huruf besar diikuti dengan huruf kecil atau angka yaitu awal dari urutan berikutnya); atau
    • satu atau lebih huruf kecil atau angka.
cletus
sumber
9
Ia bekerja untuk string CamelCased (seperti yang diminta openfrog), tetapi jika Anda menggunakannya dengan string masukan misalnya "r_id" (sudah "digarisbawahi") ia memangkas awalan ("r_"). Solusi bagus, tapi jelas tidak universal.
Martin
1
Penasaran mengapa Anda memeriksa apakah string cocok dengan string huruf kapital semua? Apa manfaat mengonversi karakter pertama menjadi huruf kecil (sebagai lawan dari semua karakter)?
Josh
1
Solusi yang lebih ringkas yang juga dapat menangani semua kasus penggunaan ini: stackoverflow.com/a/35719689/4328383
Syone
156

Solusi yang lebih singkat: Mirip dengan solusi editor dengan ekspresi reguler yang disederhanakan dan memperbaiki masalah "trailing-underscore":

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

Demo PHP | Demo Regex


Perhatikan bahwa kasus seperti SimpleXMLakan diubah simple_x_m_lmenggunakan solusi di atas. Itu juga dapat dianggap sebagai penggunaan notasi huruf besar yang salah (benar akan SimpleXml) daripada bug algoritma karena kasus seperti itu selalu ambigu - bahkan dengan mengelompokkan karakter huruf besar ke satu string ( simple_xml) algoritma seperti itu akan selalu gagal dalam kasus tepi lainnya seperti XMLHTMLConverteratau kata satu huruf dekat singkatan, dll. Jika Anda tidak keberatan tentang kasus tepi (agak jarang) dan ingin menangani SimpleXMLdengan benar, Anda dapat menggunakan solusi yang sedikit lebih kompleks:

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

Demo PHP | Demo Regex

Jan Jakeš
sumber
Jangan ragu untuk mengomentari jawaban cletus yang merinci kasus uji mana yang Anda perbaiki.
Mike B
3
Saya tidak mengatakan solusinya memberikan hasil yang salah. Solusinya sangat rumit dan tidak efektif.
Jan Jakeš
1
Ya, jawaban terima pasti gagal. Solusi Jan luar biasa! Sebagai catatan tambahan, saya pikir ini (atau sedikit variasi) adalah tes pengkodean favorit saya yang baru untuk pengembang PHP, karena jumlah jawaban yang diberikan untuk pertanyaan ini yang sebenarnya tidak berfungsi luar biasa. Ini akan menjadi cara yang bagus untuk melakukan pemfilteran awal. :-)
JamesG
menemukan regex yang digunakan dalam solusi ini jauh lebih lengkap: stackoverflow.com/questions/2559759/…
thoroc
2
Solusi bagus untuk kasus penggunaan sederhana dan dalam kebanyakan kasus biasa itu cukup, tetapi solusi yang diterima dapat menangani lebih banyak kasus penggunaan, misalnya "simpleXML" dapat diubah menjadi "simple_xml" dan bukan "simple_x_m_l"
Syone
35

Solusi singkat dan dapat menangani beberapa kasus penggunaan yang rumit:

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

Dapat menangani semua kasus ini:

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

Anda dapat menguji fungsi ini di sini: http://syframework.alwaysdata.net/decamelize

Syone
sumber
@VivekVardhan bagian mana dari ekspresi reguler ini yang tidak Anda pahami?
Syone
Uhm, menurut saya string non unta huruf kecil adalah efek samping, jika string tidak dalam format unta, string asli harus dikembalikan. Infact jika Anda mengirim 'simple_Text' Anda mendapatkan Fail: simple_Test => simple_Test [simple_test]. String huruf kecil harus dibuat hanya dan jika hanya string asli yang merupakan string case unta asli. Apa yang Anda pikirkan?
guido
24

Diangkut dari Ruby String#camelizedan 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); 
}

Salah satu trik yang mungkin terlewatkan oleh solusi di atas adalah pengubah 'e' yang menyebabkan preg_replacemengevaluasi string pengganti sebagai kode PHP.

pengguna644783
sumber
10
The ebendera untuk preg_replaceyaitu yang usang dalam PHP 5.5.
cdmckay
BTW ini juga tidak ada di Ruby, tetapi di perpustakaan inflektor Rails - camelize dan underscore. api.rubyonrails.org/classes/ActiveSupport/Inflector.html
mahemoff
2
Ini gagal untuk "ThisIsATest". Sepertinya itu tidak mendukung dua huruf besar berturut-turut.
OnaBai
Sekadar catatan: Anda dapat menggunakan lcfirst untuk mendapatkan huruf pertama menjadi huruf kecil, lalu Anda tidak memerlukan ^|atau strlen.
Benubird
mendekamelisasi tanpa penghentian: gist.github.com/scones/e09c30e696246fda14578bcf8ab4910a
scone
23

The Symfony Serializer Komponen memiliki CamelCaseToSnakeCaseNameConverter yang memiliki dua metode normalize()dan denormalize(). Ini dapat digunakan sebagai berikut:

$nameConverter = new CamelCaseToSnakeCaseNameConverter();

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

echo $nameConverter->denormalize('snake_case');
// outputs: snakeCase
matthew
sumber
1
Awas! $nameConverter->normalize('CamelCase')output _camel_casedalam versi 3.2 dari Symfony Serializer Component.
spackmat
21

Sebagian besar solusi di sini terasa berat. Inilah yang saya gunakan:

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

"CamelCASE" diubah menjadi "camel_case"

  • lcfirst($camelCase) akan menurunkan karakter pertama (hindari keluaran yang dikonversi 'CamelCASE' untuk memulai dengan garis bawah)
  • [A-Z] menemukan huruf kapital
  • + akan memperlakukan setiap huruf besar yang berurutan sebagai sebuah kata (hindari 'CamelCASE' untuk diubah menjadi camel_C_A_S_E)
  • Pola dan penggantian kedua adalah untuk ThoseSPECCases->, those_spec_casesbukanthose_speccases
  • strtolower([…]) mengubah keluaran menjadi huruf kecil
buley
sumber
3
Tapi itu juga mengubah CamelCased menjadi _camel_cased.
puncak
1
ini bagus - cukup tambahkan substr mulai dari karakter 1 untuk mengatasi masalah itu.
Oddman
4
Luar biasa! Hanya perlu menambahkan lcfirstfungsi ke $
camelCase
Jawaban yang diterima akan menangani: TestUPSClass menjadi test_ups_class sementara ini akan mengubahnya menjadi test_u_p_s_class, sesuatu yang perlu diingat.
Mazzy
String masukan yang dimulai dengan "kata" pertama allcaps akan tiba-tiba dipisahkan oleh solusi ini karena ucfirst()panggilan tersebut. USADollarSymbolmenjadi u_sa_dollar_symbol Demo Saya tidak merekomendasikan solusi ini karena harus membuat dua lintasan melalui string input dengan regex - tanda pola yang tidak dimurnikan.
mickmackusa
19

php tidak menawarkan fungsi bawaan untuk afaik ini, tapi inilah yang saya gunakan

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

}

splitter dapat ditentukan dalam pemanggilan fungsi, sehingga Anda dapat memanggilnya seperti itu

$camelized="thisStringIsCamelized";
echo uncamelize($camelized,"_");
//echoes "this_string_is_camelized"
echo uncamelize($camelized,"-");
//echoes "this-string-is-camelized"
ekhaled
sumber
2
Ini gagal untuk "ThisIsATest". Sepertinya itu tidak mendukung dua huruf besar berturut-turut.
OnaBai
Tentunya Anda lupa sesuatu karena pengganti kedua tidak melakukan apa-apa. Selain itu, Anda dapat dengan mudah membuatnya kompatibel dengan unicode mb_strtolowerdan /uopsi aktif preg_replace.
bodo
8

Anda perlu menjalankan regex yang cocok dengan setiap huruf besar kecuali di awal dan menggantinya dengan garis bawah ditambah huruf itu. Solusi utf-8 adalah ini:

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

Jika Anda tidak yakin dengan huruf besar apa string Anda, lebih baik periksa dulu, karena kode ini mengasumsikan bahwa masukannya camelCasebukan underscore_Caseatau dash-Case, jadi jika latters memiliki huruf besar, itu akan menambahkan garis bawah ke dalamnya.

Jawaban yang diterima dari cletus terlalu rumit dan hanya berfungsi dengan karakter latin. Saya merasa itu solusi yang sangat buruk dan bertanya-tanya mengapa itu diterima sama sekali. Mengubah TEST123Stringmenjadi test123_stringbelum tentu merupakan persyaratan yang valid. Saya lebih suka membuatnya sederhana dan dipisahkan ABCcccmenjadi a_b_ccccbukan ab_cccckarena tidak kehilangan informasi dengan cara ini dan konversi mundur akan memberikan string yang sama persis dengan yang kita mulai. Meskipun Anda ingin melakukannya dengan cara lain, relatif mudah untuk menulis regex untuknya dengan tampilan positif (?<!^)\p{Lu}\p{Ll}|(?<=\p{Ll})\p{Lu}atau dua ekspresi reguler tanpa tampilan belakang jika Anda bukan ahli ekspresi reguler. Tidak perlu membaginya menjadi beberapa substring, apalagi memutuskan antara strtolowerdan di lcfirstmana menggunakan just strtolowerakan baik-baik saja.

inf3rno
sumber
Jawaban kode-saja bernilai rendah di Stackoverflow karena sangat sedikit membantu mendidik / memberdayakan ribuan peneliti masa depan.
mickmackusa
@mickmackusa Jika peneliti mempelajari cara membuat kode dari SO, maka kami memiliki masalah serius ...
inf3rno
Sekarang setelah serangan pribadi itu keluar dari sistem Anda, harap perbaiki jawaban Anda. Dengan asumsi bahwa Anda tahu bagaimana solusi Anda bekerja dan mengapa Anda menggunakan pengubah pola tersebut, saya tidak melihat alasan yang baik untuk menahan pengetahuan dari komunitas ini. Jika Anda mempertimbangkan untuk meninggalkan tanggapan yang lebih tajam, saya jamin bahwa itu tidak mengganggu saya. Pada saat Anda memberikan komentar, Anda dapat menyelesaikan jawaban Anda, kami dapat menghapus komentar kami, dan saya dapat pergi ke tempat lain untuk membantu situs ini.
mickmackusa
Tentu saja, saya tidak memiliki kewenangan untuk menghapus postingan dengan 8 suara positif. Jika Anda mau, Anda dapat menghapus jawaban Anda, tetapi tidak akan terlalu sulit untuk memperbaikinya dengan menghapus pengubah pola yang tidak perlu dan menambahkan penjelasan. Serangan pribadi tidak berpengaruh pada saya.
mickmackusa
@mickmackusa Saya rasa saya juga tidak bisa menghapusnya. Jangan ragu untuk mengeditnya jika Anda mau.
inf3rno
6

Jika Anda mencari versi PHP 5.4 dan jawaban yang lebih baru di sini adalah kodenya:

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

} 
shacharsol.dll
sumber
camelize menghasilkan "SmsSent" untuk sms_sent, Anda memerlukan lcfirst
mik3fly-4steri5k
4

Tidak mewah sama sekali tapi sederhana dan cepat sekali:

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
Edakos
sumber
++$ialih-alih $i++membuatnya sedikit lebih cepat juga;)
Mathieu Amiot
Jawaban kode-saja bernilai rendah di Stackoverflow karena sangat sedikit membantu mendidik / memberdayakan ribuan peneliti masa depan.
mickmackusa
4

"CamelCase" menjadi "camel_case":

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

atau:

function camelToSnake($camel)
{
    $snake = preg_replace_callback('/[A-Z]/', function ($match){
        return '_' . strtolower($match[0]);
    }, $camel);
    return ltrim($snake, '_');
}
xiaojing
sumber
Terima kasih. Saya menggunakan pendekatan pertama, tetapi dengan tanda hubung untuk menghasilkanthis-kind-of-output
thexpand
3

Versi yang tidak menggunakan regex dapat ditemukan di sumber 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);
}
Darrell Brogdon
sumber
2
Seperti inilah kehidupan tanpa regex :-)
ekhaled
4
Heh, ya. RegEx pasti memiliki kelebihannya. :) Kecepatan mentah bukanlah salah satunya.
Darrell Brogdon
mendapat beberapa hasil lucu dengan yang satu ini karena alasan tertentu
mr1031011
Tidak berfungsi untuk saya berdasarkan string ini: "CamelCaseTestAAATestAA", seharusnya memiliki: "camel_case_test_a_a_a_test_a_a", memiliki: "" camel_case_test_aest "...
Sybio
3

Jadi ini satu baris:

strtolower(preg_replace('/(?|([a-z\d])([A-Z])|([^\^])([A-Z][a-z]))/', '$1_$2', $string));
anjing laut
sumber
Bagus, tetapi itu hanya mengubah tampilan pertama, jadi saya akan merekomendasikan untuk menambahkan gpengubah ke regex ini.
acme
@ acme, saya menggunakannya tanpa gdan berfungsi dengan baik untuk saya.
Seelts
Untuk beberapa alasan dalam kasus saya, saya harus menambahkan g. Tapi saya tidak ingat frase yang saya uji.
puncak
3

danielstjules / Stringy menyediakan metode untuk mengubah string dari camelcase ke snakecase.

s('TestUCase')->underscored(); // 'test_u_case'
Jimmy Ko
sumber
3

Laravel 5.6 menyediakan cara yang sangat sederhana untuk melakukan ini:

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

Apa fungsinya: jika terlihat bahwa setidaknya ada satu huruf kapital dalam string yang diberikan, ia menggunakan a lookahead positif untuk mencari karakter apa pun ( .) diikuti dengan huruf kapital ( (?=[A-Z])). Ini kemudian menggantikan karakter yang ditemukan dengan nilainya diikuti oleh pemisah _.

Valdrinium
sumber
Fungsi ini sekarang tampaknya disebut snake_case () dan berada di namespace global.
Wotuu
2

Port langsung dari rel (tanpa penanganan khusus untuk :: atau akronim) akan menjadi

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

Mengetahui PHP, ini akan lebih cepat daripada penguraian manual yang terjadi di jawaban lain yang diberikan di sini. Kerugiannya adalah Anda tidak bisa memilih apa yang akan digunakan sebagai pemisah antar kata, tetapi itu bukan bagian dari pertanyaan.

Juga periksa kode sumber rel yang relevan

Perhatikan bahwa ini dimaksudkan untuk digunakan dengan pengenal ASCII. Jika Anda perlu melakukan ini dengan karakter di luar rentang ASCII, gunakan pengubah '/ u' untuk preg_matchdan digunakan mb_strtolower.

pilif
sumber
Anda bisa, jika Anda hanya menambahkan parameter yang berisi karakter yang diinginkan.
Fleshgrinder
2

Inilah kontribusi saya untuk pertanyaan berusia enam tahun dengan entah berapa banyak jawaban ...

Ini akan mengubah semua kata dalam string yang disediakan yang ada di camelcase menjadi snakecase. Misalnya "SuperSpecialAwesome dan juga FizBuzz καιΚάτιΑκόμα" akan diubah menjadi "super_special_awesome dan juga fizz_buzz και_κάτι_ακόμα".

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

Yii2 memiliki fungsi berbeda untuk membuat kata snake_case dari 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));
    }
Anil Chaudhari
sumber
2

Solusi singkat:

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

Saya memiliki masalah serupa tetapi tidak dapat menemukan jawaban yang memuaskan tentang cara mengonversi CamelCase ke snake_case, sambil menghindari garis bawah duplikat atau berlebihan _ untuk nama dengan garis bawah, atau singkatan huruf besar semua.

Masalahnya adalah sebagai berikut:

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

Solusi yang saya tulis adalah panggilan dua fungsi sederhana, huruf kecil dan cari dan ganti untuk huruf kecil-besar yang berurutan:

strtolower(preg_replace("/([a-z])([A-Z])/", "$1_$2", $name));
MMS
sumber
Sejauh ini, ini adalah solusi IMO yang paling ringkas dan berguna.
Tn. 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);
}
Kurt Zhong
sumber
Anda dapat mengakses karakter secara langsung menggunakan $name{$k}(atau $name[$k]), yang akan membuat kode Anda lebih panjang, tetapi menghindari overhead besar untuk mengonversinya ke dan dari larik.
bodo
Jawaban kode-saja bernilai rendah di StackOverflow karena mereka melakukan pekerjaan yang buruk dalam memberdayakan / mendidik peneliti masa depan. Solusi Anda, sambil menghindari keanggunan regex, sangat berat dan berbelit-belit. Anda memisahkan setiap karakter dan membuat beberapa panggilan fungsi berulang. Tidak perlu menominasikan string kosong sebagai lem. Saya tidak akan menghibur solusi ini di salah satu proyek saya karena tidak ada keanggunan, mudah dibaca rendah, dan n jumlah panggilan fungsi yang tidak perlu.
mickmackusa
1

Jawaban terburuk di sini sangat dekat dengan yang terbaik (gunakan kerangka kerja). JANGAN JANGAN, lihat saja kode sumbernya. melihat apa yang digunakan kerangka kerja mapan akan menjadi pendekatan yang jauh lebih andal (dicoba dan diuji). Kerangka Zend memiliki beberapa filter kata yang sesuai dengan kebutuhan Anda. Sumber .

berikut adalah beberapa metode yang saya adaptasi dari sumbernya.

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");
TarranJones
sumber
1

Ada perpustakaan yang menyediakan fungsionalitas ini:

SnakeCaseFormatter::run('CamelCase'); // Output: "camel_case"
Kolyunya
sumber
1
Saya rasa maksud Anda "Saya telah membuat perpustakaan yang menyediakan fungsi ini". Tidak ada yang salah dengan promosi diri, tapi jangan disembunyikan.
icc97
1

Ini adalah salah satu cara yang lebih singkat:

function camel_to_snake($input)
{
    return strtolower(ltrim(preg_replace('/([A-Z])/', '_\\1', $input), '_'));
}
Ayman Gado
sumber
Jawaban kode-saja bernilai rendah di Stackoverflow karena sangat sedikit membantu mendidik / memberdayakan ribuan peneliti masa depan.
mickmackusa
1
@mickmackusa - ribuan peneliti masa depan akan tertarik pada one-liner yang elegan, dan mendidik diri sendiri.
Teson
Saya minta maaf karena Anda telah mengambil sikap egois itu. Anda pasti bisa menambahkan penjelasan dalam waktu yang dibutuhkan untuk merancang dan mengetik balasan yang tajam itu. Jawaban Anda membuat tiga panggilan fungsi, tetapi yang lain melakukan tugas dalam dua fungsi.
mickmackusa
1

Cara menghapus camelize tanpa menggunakan 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;
}

Sebuah edit:

Bagaimana saya melakukannya di 2019:

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

Dan saat PHP 7.4 akan dirilis:

function toSnakeCase($str, $glue = '_') {
    return preg_replace_callback('/[A-Z]/', fn($matches) => $glue . strtolower($matches[0]), $str);
}
baldrs
sumber
1
Jawaban kode-saja bernilai rendah di StackOverflow karena mereka melakukan pekerjaan yang buruk dalam memberdayakan / mendidik peneliti masa depan. Membuat 1 hingga 3 pemanggilan fungsi pada setiap karakter dalam string kemudian dua pemanggilan fungsi lagi setelah pengulangan selesai adalah sangat berat. Saya tidak akan menemukan solusi dengan ekonomi yang buruk.
mickmackusa
Ini adalah contoh bagaimana hal itu dapat dilakukan tanpa menggunakan ekspresi reguler, bukan bagaimana seharusnya digunakan dalam produksi, jadi saya tidak mengerti maksud Anda selain itu Anda mengeluh tentang jawaban 5y / o yang memiliki satu suara positif dan tidak mungkin dilihat oleh peneliti manapun.
baldrs
Saya memberikan perhatian saya pada semua posting, tidak hanya yang mendapat suara positif atau yang terbaru. Saya tidak mengeluh, saya memberikan kritik agar peneliti yang kurang pengetahuan dapat lebih memahami perbedaan jawaban ini dengan jawaban lainnya. Anda dapat menjelaskan di postingan Anda bahwa menghindari ekspresi reguler hanyalah tantangan akademis. Meskipun demikian, ada cara untuk membuat proses ini lebih efisien dengan praktik pengkodean yang lebih baik.
mickmackusa
0

Sangat mudah menggunakan kelas Filter dari 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

mudah >>> Mudah

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

mudah >>> mudah

HTML >>> html

simpleXML >>> simple_xml

PDFLoad >>> pdf_load

startMIDDLETerakhir >>> start_middle_last

AString >>> a_string

Some4Numbers234 >>> some4_numbers234

TEST123String >>> test123_string

automatix.dll
sumber
0

Pustaka TurboCommons open source berisi metode formatCase () tujuan umum di dalam kelas StringUtils, yang memungkinkan Anda mengonversi string ke banyak format kasus umum, seperti CamelCase, UpperCamelCase, LowerCamelCase, snake_case, Title Case, dan banyak lagi.

https://github.com/edertone/TurboCommons

Untuk menggunakannya, impor file phar ke proyek Anda dan:

use org\turbocommons\src\main\php\utils\StringUtils;

echo StringUtils::formatCase('camelCase', StringUtils::FORMAT_SNAKE_CASE);

// will output 'camel_Case'
Jaume Mussons Abad
sumber
0
$str = 'FooBarBaz';

return strtolower(preg_replace('~(?<=\\w)([A-Z])~', '_$1', $str)); // foo_bar_baz
Omar Makled
sumber
1
Jawaban kode-saja bernilai rendah di StackOverflow karena mereka melakukan pekerjaan yang buruk dalam memberdayakan / mendidik peneliti masa depan.
mickmackusa
-1

JIKA Anda bisa mulai dengan:

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

Kemudian Anda dapat mengonversi ke salah satu kasus hanya dengan:

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

Atau kasus lainnya:

$capitalized = str_replace("_", " ", $string); // Camel Case
$constant = strtoupper($string);               // CAMEL_CASE
$train = str_replace("_", "-", $snake);        // camel-case
Nuno Rafael Figueiredo
sumber