Làm cách nào để chuyển đổi PascalCase sang pascal_case?


Câu trả lời:


163

Hãy thử điều này cho kích thước:

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

Đầu ra:

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

Điều này thực hiện các quy tắc sau:

  1. Một chuỗi bắt đầu bằng một chữ cái viết thường phải được theo sau bởi các chữ cái và chữ số viết thường;
  2. Một chuỗi bắt đầu bằng một chữ cái viết hoa có thể được theo sau bởi:
    • một hoặc nhiều chữ cái và chữ số viết hoa (theo sau là phần cuối của chuỗi hoặc một chữ cái viết hoa theo sau là chữ cái viết thường hoặc chữ số, tức là bắt đầu chuỗi tiếp theo); hoặc là
    • một hoặc nhiều chữ cái thường hoặc chữ số.

9
Nó hoạt động cho các chuỗi CamelCase (như openfrog đã hỏi), nhưng nếu bạn sử dụng nó với chuỗi đầu vào, ví dụ "r_id" (đã "gạch dưới"), nó sẽ cắt bớt tiền tố ("r_"). Giải pháp tốt, nhưng chắc chắn không phải là phổ quát.
Martin

1
Tò mò tại sao bạn đang kiểm tra xem chuỗi có khớp với chuỗi all-caps không? Lợi ích của việc chuyển đổi chỉ ký tự đầu tiên thành chữ thường (trái ngược với tất cả các ký tự) là gì?
Josh

1
Một giải pháp ngắn gọn hơn cũng có thể xử lý tất cả các trường hợp sử dụng này: stackoverflow.com/a/35719689/4328383
Syone

155

Một giải pháp ngắn hơn: Tương tự như giải pháp của trình soạn thảo với biểu thức chính quy đơn giản hóa và khắc phục sự cố "dấu gạch dưới":

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

Trình diễn PHP | Bản giới thiệu Regex


Lưu ý rằng các trường hợp như SimpleXMLsẽ được chuyển đổi sang simple_x_m_lsử dụng giải pháp trên. Điều đó cũng có thể được coi là sử dụng sai ký hiệu trường hợp lạc đà (chính xác SimpleXml) chứ không phải là lỗi của thuật toán vì các trường hợp như vậy luôn mơ hồ - ngay cả khi nhóm các ký tự viết hoa thành một chuỗi ( simple_xml) thuật toán như vậy sẽ luôn thất bại trong các trường hợp cạnh khác những từ thích XMLHTMLConverterhoặc một chữ cái gần chữ viết tắt, v.v ... Nếu bạn không bận tâm về các trường hợp cạnh (khá hiếm) và muốn xử lý SimpleXMLchính xác, bạn có thể sử dụng một giải pháp phức tạp hơn một chút:

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

Trình diễn PHP | Bản giới thiệu Regex


Hãy bình luận về câu trả lời của cletus nêu chi tiết những trường hợp kiểm tra mà bạn đã sửa.
Mike B

3
Tôi không nói rằng giải pháp của anh ấy cho kết quả sai. Giải pháp của anh ta cực kỳ phức tạp và không hiệu quả.
Jan Jakeš

1
Đúng, câu trả lời chấp nhận chắc chắn là một thất bại. Giải pháp của Jan thật tuyệt vời! Là một lưu ý phụ, tôi nghĩ rằng điều này (hoặc một biến thể nhỏ) là bài kiểm tra mã hóa mới, yêu thích của tôi dành cho các nhà phát triển PHP, bởi vì số lượng câu trả lời được cung cấp cho câu hỏi này không thực sự hoạt động là không thể tin được. Nó sẽ là một cách tuyệt vời để thực hiện việc lọc ban đầu. :-)
JamesG

tìm thấy regex được sử dụng trong giải pháp này đầy đủ hơn nhiều: stackoverflow.com/questions/2559759/ trên
thoroc 19/2/2016

2
Giải pháp tuyệt vời cho các trường hợp sử dụng đơn giản và trong hầu hết các trường hợp thông thường là đủ nhưng giải pháp được chấp nhận có thể xử lý nhiều trường hợp sử dụng hơn, ví dụ "SimpleXML" có thể được chuyển đổi thành "simple_xml" chứ không phải "Simple_x_m_l"
Syone

35

Một giải pháp ngắn gọn và có thể xử lý một số trường hợp sử dụng khó khăn:

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

Có thể xử lý tất cả các trường hợp sau:

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

Bạn có thể kiểm tra chức năng này tại đây: http://syframework.alwaysdata.net/decamelize


@VivekVardhan phần nào của regex này bạn không hiểu?
Syone

Uhm, tôi nghĩ rằng việc hạ thấp các chuỗi không phải camelcase là một tác dụng phụ, trong trường hợp chuỗi không ở định dạng trường hợp lạc đà, chuỗi gốc sẽ được trả về. Nguyên vẹn nếu bạn gửi 'Simple_Text', bạn nhận được Fail: simple_Test => simple_Test [simple_test]. Chuỗi hạ thấp chỉ nên được thực hiện và nếu chỉ chuỗi gốc là chuỗi trường hợp lạc đà thực sự. Bạn nghĩ về điều gì?
guido

24

Chuyển từ Ruby String#camelizeString#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); 
}

Một mẹo mà các giải pháp trên có thể đã bỏ lỡ là công cụ sửa đổi 'e' gây ra preg_replaceđể đánh giá chuỗi thay thế dưới dạng mã PHP.


10
Các elá cờ cho preg_replacelà bị phản đối trong PHP 5.5.
cdmckay

BTW cũng không có trong Ruby, nhưng trong thư viện bộ lọc của Rails - camelize và gạch dưới. api.rubyonrails.org/groupes/ActiveSupport/Inflector.html
mahemoff

2
Điều này không thành công cho "ThisIsATest". Có vẻ như không hỗ trợ hai chữ hoa liên tiếp.
OnaBai

Chỉ cần một lưu ý: bạn có thể sử dụng lcfirst để lấy chữ cái đầu tiên viết thường, sau đó bạn không cần ^|hoặc strlen.
Benubird


23

Các Symfony Serializer ComponentCamelCaseToSnakeCaseNameConverter rằng có hai phương pháp normalize()denormalize(). Chúng có thể được sử dụng như sau:

$nameConverter = new CamelCaseToSnakeCaseNameConverter();

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

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

1
Coi chừng! $nameConverter->normalize('CamelCase')đầu ra _camel_casetrong phiên bản 3.2 hiện tại của Thành phần nối tiếp Symfony.
spackmat

21

Hầu hết các giải pháp ở đây đều cảm thấy nặng tay. Đây là những gì tôi sử dụng:

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

"CamelCASE" được chuyển đổi thành "camel_case"

  • lcfirst($camelCase) sẽ hạ thấp ký tự đầu tiên (tránh đầu ra được chuyển đổi 'CamelCASE' để bắt đầu bằng dấu gạch dưới)
  • [A-Z] tìm chữ in hoa
  • + sẽ coi mọi chữ hoa liên tiếp là một từ (tránh 'CamelCASE' được chuyển đổi thành camel_C_A_S_E)
  • Mẫu thứ hai và thay thế là cho ThoseSPECCases-> those_spec_casesthay vìthose_speccases
  • strtolower([…]) biến đầu ra thành chữ thường

3
Nhưng nó cũng biến CamelCase thành _camel_casing.
acme 18/07/13

1
điều này thật tuyệt - chỉ cần thêm một nền tảng bắt đầu từ char 1 để giải quyết vấn đề đó.
Oddman

4
Tuyệt vời! Chỉ cần thêm lcfirstchức năng vào $ camelCase
Edakos 16/12/13

Câu trả lời được chấp nhận sẽ xử lý: TestUPSClass thành test_ups_group trong khi điều này sẽ biến nó thành test_u_p_s_group, một điều cần lưu ý.
Mazzy

Một chuỗi đầu vào bắt đầu bằng một từ "all" đầu tiên sẽ bị chia tách bất ngờ bởi giải pháp này vì ucfirst()cuộc gọi. USADollarSymboltrở thành bản u_sa_dollar_symbol Demo Tôi không đề xuất giải pháp này vì nó phải thực hiện hai lần đi qua chuỗi đầu vào với regex - một dấu hiệu của một mẫu chưa tinh chỉnh.
mickmackusa

19

php không cung cấp chức năng tích hợp cho afaik này, nhưng đây là những gì tôi sử dụng

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

}

bộ chia có thể được chỉ định trong lệnh gọi hàm, vì vậy bạn có thể gọi nó như vậy

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

2
Điều này không thành công cho "ThisIsATest". Có vẻ như không hỗ trợ hai chữ hoa liên tiếp.
OnaBai

Chắc chắn bạn đã quên một cái gì đó như thay thế thứ hai không làm gì. Ngoài ra, bạn có thể dễ dàng làm cho nó unicode tương thích với mb_strtolower/utùy chọn trên preg_replace.
Bodo

8

Bạn cần chạy regex thông qua nó khớp với mọi chữ cái viết hoa trừ khi nó ở đầu và thay thế nó bằng dấu gạch dưới cộng với chữ cái đó. Một giải pháp utf-8 là thế này:

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

Nếu bạn không chắc chắn trường hợp chuỗi của bạn là gì, tốt hơn là kiểm tra nó trước, bởi vì mã này giả định rằng đầu vào là camelCasethay vì underscore_Casehoặc dash-Case, vì vậy nếu các latters có chữ in hoa, nó sẽ thêm dấu gạch dưới cho chúng.

Câu trả lời được chấp nhận từ cletus là imho quá phức tạp và nó chỉ hoạt động với các ký tự Latin. Tôi thấy đó là một giải pháp thực sự tồi tệ và tự hỏi tại sao nó lại được chấp nhận. Chuyển đổi TEST123Stringthành test123_stringkhông nhất thiết là một yêu cầu hợp lệ. Tôi thà giữ nó đơn giản và tách ra ABCcccvào a_b_ccccthay vì ab_ccccbởi vì nó thông tin không mất theo cách này và việc chuyển đổi ngược sẽ cung cấp cho các chuỗi chính xác cùng chúng tôi bắt đầu với. Ngay cả khi bạn muốn làm theo cách khác, việc viết regex cho nó với giao diện tích cực (?<!^)\p{Lu}\p{Ll}|(?<=\p{Ll})\p{Lu}hoặc hai regex không có lookbehind là tương đối dễ dàng nếu bạn không phải là chuyên gia về regex. Không cần phải chia nó thành các chuỗi con, chưa kể đến việc quyết định giữa strtolowerlcfirstnơi sử dụng strtolowersẽ hoàn toàn tốt.


Các câu trả lời chỉ có mã là giá trị thấp trên Stackoverflow vì chúng làm rất ít để giáo dục / trao quyền cho hàng ngàn nhà nghiên cứu trong tương lai.
mickmackusa

@mickmackusa Nếu các nhà nghiên cứu học cách viết mã từ SO, thì chúng ta có một vấn đề nghiêm trọng ...
inf3rno

Bây giờ bạn đã có được cuộc tấn công cá nhân đó ra khỏi hệ thống của bạn, vui lòng cải thiện câu trả lời của bạn. Giả sử rằng bạn biết giải pháp của bạn hoạt động như thế nào và tại sao bạn đang sử dụng các công cụ sửa đổi mẫu đó, tôi thấy không có lý do chính đáng nào để giữ lại kiến ​​thức từ cộng đồng này. Trong trường hợp bạn đang cân nhắc để lại nhiều phản hồi lén lút hơn, tôi đảm bảo với bạn rằng họ không làm phiền tôi. Trong thời gian bạn đưa ra nhận xét, bạn có thể đã hoàn thành câu trả lời của mình, chúng tôi có thể đã xóa nhận xét của chúng tôi và tôi có thể đã đi nơi khác để giúp trang web này.
mickmackusa

Tất nhiên, tôi không có thẩm quyền để xóa một bài đăng với 8 lượt upvote. Nếu bạn muốn, bạn có thể xóa câu trả lời của mình, nhưng sẽ rất khó để cải thiện nó bằng cách loại bỏ các sửa đổi mẫu không cần thiết và thêm một lời giải thích. Các cuộc tấn công cá nhân không có tác dụng đối với tôi.
mickmackusa

@mickmackusa Tôi cũng không nghĩ mình có thể xóa nó. Hãy chỉnh sửa nó nếu bạn muốn.
inf3rno

6

Nếu bạn đang tìm kiếm một phiên bản PHP 5.4 và sau đó trả lời ở đây là mã:

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 sản xuất "SmsSent" cho sms_sent, bạn cần một lcfirst
mik3fly-4steri5k

4

Không lạ mắt chút nào nhưng đơn giản và nhanh chóng như địa ngục:

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

++$ithay vì $i++sẽ làm cho nó nhanh hơn một chút nữa;)
Mathieu Amiot

Các câu trả lời chỉ có mã là giá trị thấp trên Stackoverflow vì chúng làm rất ít để giáo dục / trao quyền cho hàng ngàn nhà nghiên cứu trong tương lai.
mickmackusa

4

"CamelCase" thành "camel_case":

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

hoặc là:

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

Cảm ơn bạn. Tôi đã sử dụng cách tiếp cận đầu tiên, nhưng với dấu gạch nối để tạothis-kind-of-output
thexpand

3

Phiên bản không sử dụng regex có thể được tìm thấy trong nguồn 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);
}

1
Đây là cuộc sống sẽ như thế nào nếu không có regex :-)
ekhaled

4
Heh, vâng. RegEx chắc chắn có lợi thế của nó. :) Tốc độ thô không phải là một trong số họ.
Darrell Brogdon

vì một số kết quả hài hước với kết quả này vì một số lý do
mr1031011

Không hoạt động đối với tôi dựa trên chuỗi này: "CamelCaseTestAAATestAA", nên có: "camel_case_test_a_a_a_test_a_a", có: "" camel_case_test_aest "...
Sybio

3

Vì vậy, đây là một lót:

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

Đẹp, nhưng nó chỉ chuyển đổi diện mạo đầu tiên, vì vậy tôi khuyên bạn nên thêm một gsửa đổi cho regex này.
acme

@acme, tôi sử dụng nó mà không có gvà nó hoạt động tốt với tôi.
seelts

Vì một số lý do trong trường hợp của tôi, tôi đã phải thêm g. Nhưng tôi không thể nhớ cụm từ tôi đã thử nghiệm.
acme


3

Laravel 5.6 cung cấp một cách rất đơn giản để làm điều này:

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

Nó làm gì: nếu nó thấy rằng có ít nhất một chữ cái in hoa trong chuỗi đã cho, nó sử dụng một cái nhìn tích cực để tìm kiếm bất kỳ ký tự ( .) nào theo sau là chữ in hoa ( (?=[A-Z])). Sau đó, nó thay thế ký tự tìm thấy bằng giá trị của nó, theo sau là dấu phân cách _.


Hàm này bây giờ dường như được gọi là Snake_case () và sống trong không gian tên toàn cầu.
Wotuu

2

Cổng trực tiếp từ đường ray (trừ xử lý đặc biệt của họ cho :: hoặc từ viết tắt) sẽ là

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

Biết PHP, điều này sẽ nhanh hơn so với phân tích cú pháp thủ công xảy ra trong các câu trả lời khác được đưa ra ở đây. Nhược điểm là bạn không được chọn sử dụng phân tách giữa các từ, nhưng đó không phải là một phần của câu hỏi.

Cũng kiểm tra mã nguồn đường ray có liên quan

Lưu ý rằng điều này được thiết kế để sử dụng với các định danh ASCII. Nếu bạn cần thực hiện việc này với các ký tự nằm ngoài phạm vi ASCII, hãy sử dụng công cụ sửa đổi '/ u' cho preg_matchvà sử dụng mb_strtolower.


Bạn có thể, nếu bạn chỉ cần thêm một tham số có chứa ký tự mong muốn.
F Meatgrinder 14/11 '

2

Đây là đóng góp của tôi cho một câu hỏi sáu năm tuổi với chúa biết có bao nhiêu câu trả lời ...

Nó sẽ chuyển đổi tất cả các từ trong chuỗi được cung cấp trong camelcase thành snakecase. Ví dụ: "SuperecialAwgie và cả FizBuzz κiatedΚάτιΑκόμα" sẽ được chuyển đổi thành "super_special_awemme và cả fizz_buzz κiated_κάτι_ακόμα".

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

2

Yii2 có chức năng khác nhau để tạo từ Snake_case từ 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

Giải pháp ngắn gọn:

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

2

Tôi đã gặp một vấn đề tương tự nhưng không thể tìm thấy bất kỳ câu trả lời nào thỏa mãn cách chuyển đổi CamelCase thành Snake_case, đồng thời tránh trùng lặp hoặc thừa các dấu gạch dưới _ cho các tên có dấu gạch dưới hoặc tất cả các chữ viết tắt.

Vấn đề như sau:

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

Giải pháp tôi đã viết là một hàm đơn giản gọi, viết thường và tìm kiếm và thay thế cho các chữ cái viết thường liên tiếp:

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

Cho đến nay đây là giải pháp IMO ngắn gọn và hữu ích nhất.
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);
}

Bạn có thể truy cập các ký tự trực tiếp bằng cách sử dụng $name{$k}(hoặc $name[$k]), điều này sẽ làm cho mã của bạn dài hơn, nhưng tránh được chi phí lớn khi chuyển đổi nó sang và từ một mảng.
bồ đề

Các câu trả lời chỉ có mã là giá trị thấp trên StackOverflow vì chúng làm rất kém trong việc trao quyền / giáo dục các nhà nghiên cứu trong tương lai. Giải pháp của bạn, trong khi tránh ân sủng của regex, là rất nặng tay và hỗn láo. Bạn đang phân tách trên mỗi ký tự và thực hiện nhiều lệnh gọi hàm lặp. Đề cử một chuỗi rỗng như keo là không cần thiết. Tôi sẽ không giải trí giải pháp này trong một trong các dự án của mình vì không có sự tao nhã, khả năng đọc thấp và n số của các cuộc gọi chức năng không cần thiết.
mickmackusa

1

Câu trả lời tồi tệ nhất ở đây là gần như là tốt nhất (sử dụng khung). KHÔNG KHÔNG, chỉ cần xem mã nguồn. nhìn thấy những gì một khung công tác được thiết lập tốt sẽ là một cách tiếp cận đáng tin cậy hơn nhiều (đã thử và thử nghiệm). Khung Zend có một số bộ lọc từ phù hợp với nhu cầu của bạn. Nguồn .

đây là một vài phương pháp tôi điều chỉnh từ nguồn.

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ó một thư viện cung cấp chức năng này:

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

1
Tôi nghĩ bạn có nghĩa là "Tôi đã tạo ra một thư viện cung cấp chức năng này". Không có gì sai khi tự quảng cáo, nhưng đừng che giấu nó.
icc97


1

Đây là một trong những cách ngắn hơn:

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

Các câu trả lời chỉ có mã là giá trị thấp trên Stackoverflow vì chúng làm rất ít để giáo dục / trao quyền cho hàng ngàn nhà nghiên cứu trong tương lai.
mickmackusa

1
@mickmackusa - hàng ngàn nghiên cứu trong tương lai sẽ quan tâm đến một lớp lót thanh lịch và giáo dục chính họ.
Teson

Tôi xin lỗi vì bạn đã có lập trường ích kỷ đó. Bạn chắc chắn có thể đã thêm một lời giải thích trong thời gian bạn cần thiết kế và gõ câu trả lời lén lút đó. Câu trả lời của bạn thực hiện ba cuộc gọi chức năng, nhưng những người khác thực hiện nhiệm vụ trong hai.
mickmackusa

1

Cách khử camelize mà không cần sử dụng 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;
}

Một chỉnh sửa:

Làm thế nào tôi sẽ làm điều đó vào năm 2019:

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

Và khi PHP 7.4 sẽ được phát hành:

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

1
Các câu trả lời chỉ có mã là giá trị thấp trên StackOverflow vì chúng làm rất kém trong việc trao quyền / giáo dục các nhà nghiên cứu trong tương lai. Thực hiện 1 đến 3 lệnh gọi hàm trên mỗi ký tự trong chuỗi, sau đó hai lệnh gọi hàm khác sau khi vòng lặp được thực hiện rất nặng tay. Tôi sẽ không giải trí một giải pháp với nền kinh tế nghèo như vậy.
mickmackusa

Đó là một ví dụ về cách nó có thể được thực hiện mà không cần sử dụng các biểu thức thông thường, không phải là cách sử dụng nó trong sản xuất, vì vậy tôi không thấy quan điểm của bạn bên cạnh việc bạn phàn nàn về câu trả lời 5y / o có một upvote và không thể thấy được bất kỳ nhà nghiên cứu.
hói

Tôi chú ý đến tất cả các bài viết, không chỉ những bài được đánh giá cao hoặc những bài gần đây. Tôi không phàn nàn, tôi đưa ra lời phê bình của mình để các nhà nghiên cứu có ít kiến ​​thức có thể hiểu rõ hơn về sự khác biệt giữa câu trả lời này và câu trả lời khác. Bạn có thể đã giải thích trong bài viết của mình rằng đó chỉ là một thách thức học thuật để tránh regex. Điều đó nói rằng, có nhiều cách để làm cho quá trình này hiệu quả hơn với thực tiễn mã hóa tốt hơn.
mickmackusa

0

Thật dễ dàng khi sử dụng các lớp Bộ lọc của Bộ lọc Word Zend :

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

----- gạch dưới ToCamelCase -----

Simple_test >>> SimpleTest

dễ dàng >>> Dễ dàng

html >>> Html

đơn giản_xml >>> SimpleXml

pdf_load >>> Tải xuống PdfLoad

start_middle_last >>> StartMiddleLast

a_ chuỗi >>> AString

some4_numbers234 >>> some4Numbers234

test123_ chuỗi >>> Test123String

----- camelCaseToUnderscore -----

đơn giản >>> đơn giản

dễ dàng >>> dễ dàng

HTML >>> html

SimpleXML >>> Simple_xml

Tải xuống PDF >>> pdf_load

startMIDDLELast >>> start_middle_last

Bắt buộc >>> a_ chuỗi

Một số4Numbers234 >>> some4_numbers234

TEST123String >>> test123_ chuỗi


0

Thư viện TurboCommons mã nguồn mở chứa một phương thức định dạng mục đích chungCase () bên trong lớp StringUtils, cho phép bạn chuyển đổi một chuỗi thành nhiều định dạng trường hợp phổ biến, như CamelCase, UpperCamelCase, LowerCamelCase, Snake_case, Title Case, và nhiều hơn nữa.

https://github.com/edertone/TurboCommons

Để sử dụng nó, hãy nhập tệp phar vào dự án của bạn và:

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
Các câu trả lời chỉ có mã là giá trị thấp trên StackOverflow vì chúng làm rất kém trong việc trao quyền / giáo dục các nhà nghiên cứu trong tương lai.
mickmackusa

-1

NẾU bạn có thể bắt đầu với:

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

Sau đó, bạn có thể chuyển đổi sang một trong hai trường hợp chỉ với:

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

Hoặc bất kỳ trường hợp nào khác:

$capitalized = str_replace("_", " ", $string); // Camel Case
$constant = strtoupper($string);               // CAMEL_CASE
$train = str_replace("_", "-", $snake);        // camel-case
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.