如何将PascalCase转换为snake_case?

发布于 2024-08-16 19:31:02 字数 137 浏览 7 评论 0原文

如果我有:

$string = "PascalCase";

我需要

"pascal_case"

PHP 是否提供了用于此目的的函数?

If I had:

$string = "PascalCase";

I need

"pascal_case"

Does PHP offer a function for this purpose?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(30

被翻牌 2024-08-23 19:31:02

更短的解决方案:与编辑器类似,具有简化的正则表达式并修复“尾随下划线”问题:

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

PHP 演示< /a> |
正则表达式演示


请注意,像 SimpleXML 这样的情况将转换为 simple_x_m_l使用上述解决方案。这也可以被认为是驼峰式大小写表示法的错误使用(正确的是 SimpleXml),而不是算法的错误,因为这种情况总是不明确的 - 即使将大写字符分组为一个字符串(>simple_xml)这样的算法在其他边缘情况下总是会失败,例如 XMLHTMLConverter 或缩写附近的单字母单词等。如果您不介意(相当罕见的)边缘情况并且想要正确处理 SimpleXML,您可以使用稍微复杂一点的解决方案:

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

PHP Demo |
正则表达式演示

A shorter solution: Similar to the editor's one with a simplified regular expression and fixing the "trailing-underscore" problem:

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

PHP Demo |
Regex Demo


Note that cases like SimpleXML will be converted to simple_x_m_l using the above solution. That can also be considered a wrong usage of camel case notation (correct would be SimpleXml) rather than a bug of the algorithm since such cases are always ambiguous - even by grouping uppercase characters to one string (simple_xml) such algorithm will always fail in other edge cases like XMLHTMLConverter or one-letter words near abbreviations, etc. If you don't mind about the (rather rare) edge cases and want to handle SimpleXML correctly, you can use a little more complex solution:

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

PHP Demo |
Regex Demo

潦草背影 2024-08-23 19:31:02

尝试一下大小:

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

输出:

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

这实现了以下规则:

  1. 以小写字母开头的序列必须后跟小写字母和数字;
  2. 以大写字母开头的序列后面可以是:
    • 一个或多个大写字母和数字(后跟字符串的结尾或大写字母后跟小写字母或数字,即下一个序列的开始);或
    • 一个或多个小写字母或数字。

Try this on for size:

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

Output:

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

This implements the following rules:

  1. A sequence beginning with a lowercase letter must be followed by lowercase letters and digits;
  2. A sequence beginning with an uppercase letter can be followed by either:
    • one or more uppercase letters and digits (followed by either the end of the string or an uppercase letter followed by a lowercase letter or digit ie the start of the next sequence); or
    • one or more lowercase letters or digits.
远山浅 2024-08-23 19:31:02

一个简洁的解决方案,可以处理一些棘手的用例:

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

可以处理所有这些情况:

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

您可以在此处测试此功能:http:// /syframework.alwaysdata.net/decamelize

A concise solution and can handle some tricky use cases:

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

Can handle all these cases:

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

You can test this function here: http://syframework.alwaysdata.net/decamelize

长安忆 2024-08-23 19:31:02

Symfony Serializer 组件 有一个 CamelCaseToSnakeCaseNameConverter 具有两个方法 normalize()denormalize()。这些可以按如下方式使用:

$nameConverter = new CamelCaseToSnakeCaseNameConverter();

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

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

The Symfony Serializer Component has a CamelCaseToSnakeCaseNameConverter that has two methods normalize() and denormalize(). These can be used as follows:

$nameConverter = new CamelCaseToSnakeCaseNameConverter();

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

echo $nameConverter->denormalize('snake_case');
// outputs: snakeCase
丘比特射中我 2024-08-23 19:31:02

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

上述解决方案可能忽略的一个技巧是“e”修饰符,它会导致 preg_replace 将替换字符串评估为 PHP 代码。

Ported from Ruby's String#camelize and 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); 
}

One trick the above solutions may have missed is the 'e' modifier which causes preg_replace to evaluate the replacement string as PHP code.

坦然微笑 2024-08-23 19:31:02

这里的大多数解决方案都让人感觉很严厉。这是我使用的:

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

“CamelCASE”转换为“camel_case”

  • lcfirst($camelCase) 将降低第一个字符(避免“CamelCASE”转换后的输出以下划线开头)
  • [AZ] 找到大写字母
  • + 会将每个连续的大写字母视为一个单词(避免将“CamelCASE”转换为camel_C_A_S_E)
  • 第二个模式和替换用于 ThoseSPECCases -> ; those_spec_cases 而不是 those_speccases
  • strtolower([…]) 将输出转换为小写

Most solutions here feel heavy handed. Here's what I use:

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

"CamelCASE" is converted to "camel_case"

  • lcfirst($camelCase) will lower the first character (avoids 'CamelCASE' converted output to start with an underscore)
  • [A-Z] finds capital letters
  • + will treat every consecutive uppercase as a word (avoids 'CamelCASE' to be converted to camel_C_A_S_E)
  • Second pattern and replacement are for ThoseSPECCases -> those_spec_cases instead of those_speccases
  • strtolower([…]) turns the output to lowercases
打小就很酷 2024-08-23 19:31:02

php 没有为此提供内置函数,但这是我使用的

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

}

拆分器可以在函数调用中指定,因此您可以像这样调用它

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

php does not offer a built in function for this afaik, but here is what I use

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

}

the splitter can be specified in the function call, so you can call it like so

$camelized="thisStringIsCamelized";
echo uncamelize($camelized,"_");
//echoes "this_string_is_camelized"
echo uncamelize($camelized,"-");
//echoes "this-string-is-camelized"
夏九 2024-08-23 19:31:02

我遇到了类似的问题,但找不到任何满足如何将 CamelCase 转换为 Snake_case 的答案,同时避免使用带有下划线的名称或全部大写缩写的重复或冗余下划线 _

问题如下:

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

我写的解决方案是一个简单的两个函数调用,小写和搜索并替换连续的小写-大写字母:

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

I had a similar problem but couldn't find any answer that satisfies how to convert CamelCase to snake_case, while avoiding duplicate or redundant underscores _ for names with underscores, or all caps abbreviations.

Th problem is as follows:

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

The solution I wrote is a simple two functions call, lowercase and search and replace for consecutive lowercase-uppercase letters:

strtolower(preg_replace("/([a-z])([A-Z])/", "$1_$2", $name));
远山浅 2024-08-23 19:31:02

“CamelCase”到“camel_case”:

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

或:

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

"CamelCase" to "camel_case":

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

or:

function camelToSnake($camel)
{
    $snake = preg_replace_callback('/[A-Z]/', function ($match){
        return '_' . strtolower($match[0]);
    }, $camel);
    return ltrim($snake, '_');
}
墟烟 2024-08-23 19:31:02

如果您正在寻找 PHP 5.4 版本和更高版本,这里的答案是代码:

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

} 

If you are looking for a PHP 5.4 version and later answer here is the code:

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

} 
爱她像谁 2024-08-23 19:31:02

您需要通过它运行一个正则表达式来匹配每个大写字母(除非它位于开头),并将其替换为下划线加该字母。 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_áááá_őőőő

如果您不确定字符串的大小写,最好先检查一下,因为此代码假定输入是 camelCase 而不是 underscore_Case > 或 dash-Case,因此如果后者有大写字母,则会为其添加下划线。

cletus 接受的答案过于复杂,恕我直言,它仅适用于拉丁字符。我发现这是一个非常糟糕的解决方案,并且想知道为什么它会被接受。将 TEST123String 转换为 test123_string 不一定是有效的要求。我宁愿保持简单并将 ABCccc 分离为 a_b_cccc 而不是 ab_cccc 因为这样不会丢失信息,并且向后转换将给出准确的信息我们开始使用的字符串相同。即使您想以其他方式执行此操作,也可以相对轻松地使用正向lookbehind (? 或两个没有后向的正则表达式(如果您不是正则表达式专家)。无需将其拆分为子字符串,更不用说在 strtolowerlcfirst 之间做出选择,其中仅使用 strtolower 就完全没问题了。

You need to run a regex through it that matches every uppercase letter except if it is in the beginning and replace it with underscrore plus that letter. An utf-8 solution is this:

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

If you are not sure what case your string is, better to check it first, because this code assumes that the input is camelCase instead of underscore_Case or dash-Case, so if the latters have uppercase letters, it will add underscores to them.

The accepted answer from cletus is way too overcomplicated imho and it works only with latin characters. I find it a really bad solution and wonder why it was accepted at all. Converting TEST123String into test123_string is not necessarily a valid requirement. I rather kept it simple and separated ABCccc into a_b_cccc instead of ab_cccc because it does not lose information this way and the backward conversion will give the exact same string we started with. Even if you want to do it the other way it is relative easy to write a regex for it with positive lookbehind (?<!^)\p{Lu}\p{Ll}|(?<=\p{Ll})\p{Lu} or two regexes without lookbehind if you are not a regex expert. There is no need to split it up into substrings not to mention deciding between strtolower and lcfirst where using just strtolower would be completely fine.

撧情箌佬 2024-08-23 19:31:02

简短的解决方案:

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

Short solution:

$subject = "PascalCase";
echo strtolower(preg_replace('/\B([A-Z])/', '_$1', $subject));
谎言月老 2024-08-23 19:31:02

一点也不花哨,但是简单而快速:

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

Not fancy at all but simple and speedy as hell:

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
并安 2024-08-23 19:31:02

使用 Symfony 字符串

composer require symfony/string
use function Symfony\Component\String\u;

u($string)->snake()->toString()

Use Symfony String

composer require symfony/string
use function Symfony\Component\String\u;

u($string)->snake()->toString()
初与友歌 2024-08-23 19:31:02

不使用正则表达式的版本可以在 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);
}

A version that doesn't use regex can be found in the Alchitect source:

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);
}
裂开嘴轻声笑有多痛 2024-08-23 19:31:02

所以这里有一句话:

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

So here is a one-liner:

strtolower(preg_replace('/(?|([a-z\d])([A-Z])|([^\^])([A-Z][a-z]))/', '$1_$2', $string));
樱花落人离去 2024-08-23 19:31:02

danielstjules/Stringy 提供了一种将字符串从驼峰命名法转换为蛇形命名法的方法。

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

danielstjules/Stringy provieds a method to convert string from camelcase to snakecase.

s('TestUCase')->underscored(); // 'test_u_case'
相对绾红妆 2024-08-23 19:31:02

Laravel 5.6 提供了一种非常简单的方法来执行此操作:

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

它的作用:如果它发现给定字符串中至少有一个大写字母,它会使用 正向前视 搜索任何字符 (.) 后跟大写字母 ((?=[AZ])< /代码>)。然后,它将找到的字符替换为其值,后跟分隔符 _

Laravel 5.6 provides a very simple way of doing this:

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

What it does: if it sees that there is at least one capital letter in the given string, it uses a positive lookahead to search for any character (.) followed by a capital letter ((?=[A-Z])). It then replaces the found character with it's value followed by the separactor _.

只有一腔孤勇 2024-08-23 19:31:02

从 Rails 直接移植(减去对 :: 或首字母缩略词的特殊处理)将是

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

Knowing PHP,这将比此处给出的其他答案中发生的手动解析更快。缺点是您无法选择使用什么作为单词之间的分隔符,但这不是问题的一部分。

另请检查相关rails源代码

请注意,这适用于 ASCII 标识符。如果您需要对 ASCII 范围之外的字符执行此操作,请使用 preg_match 的“/u”修饰符并使用 mb_strtolower

The direct port from rails (minus their special handling for :: or acronyms) would be

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

Knowing PHP, this will be faster than the manual parsing that's happening in other answers given here. The disadvantage is that you don't get to chose what to use as a separator between words, but that wasn't part of the question.

Also check the relevant rails source code

Note that this is intended for use with ASCII identifiers. If you need to do this with characters outside of the ASCII range, use the '/u' modifier for preg_matchand use mb_strtolower.

木緿 2024-08-23 19:31:02

这是我对一个六年前问题的贡献,天知道有多少答案......

它将把提供的字符串中驼峰式的所有单词转换为蛇形式。例如,“SuperSpecialAwesome 和 FizBuzz καιKάτιAκόμα”将转换为“super_special_awesome 和 fizz_buzz και_κάτι_ακόμα”。

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

Here is my contribution to a six-year-old question with god knows how many answers...

It will convert all words in the provided string that are in camelcase to snakecase. For example "SuperSpecialAwesome and also FizBuzz καιΚάτιΑκόμα" will be converted to "super_special_awesome and also fizz_buzz και_κάτι_ακόμα".

mb_strtolower(
    preg_replace_callback(
        '/(?<!\b|_)\p{Lu}/u',
        function ($a) {
            return "_$a[0]";
        },
        'SuperSpecialAwesome'
    )
);
永不分离 2024-08-23 19:31:02

Yii2 有不同的函数来将单词“snake_case”从“CamelCase”变为“snake_case”。

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

Yii2 have the different function to make the word snake_case from 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));
    }
赠我空喜 2024-08-23 19:31:02

这是较短的方法之一:

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

This is one of shorter ways:

function camel_to_snake($input)
{
    return strtolower(ltrim(preg_replace('/([A-Z])/', '_\\1', $input), '_'));
}
烟若柳尘 2024-08-23 19:31:02

如果您没有使用 Composer for PHP,那么您就是在浪费时间。

composer require doctrine/inflector
use Doctrine\Inflector\InflectorFactory;

// Couple ways to get class name:

// If inside a parent class
$class_name = get_called_class();

// Or just inside the class
$class_name = get_class();

// Or straight get a class name
$class_name = MyCustomClass::class;

// Or, of course, a string
$class_name = 'App\Libs\MyCustomClass';

// Take the name down to the base name:
$class_name = end(explode('\\', $class_name)));

$inflector = InflectorFactory::create()->build();

$inflector->tableize($class_name); // my_custom_class

https://github.com/doctrine/inflector/blob/master/docs/en/index.rst

If you are not using Composer for PHP you are wasting your time.

composer require doctrine/inflector
use Doctrine\Inflector\InflectorFactory;

// Couple ways to get class name:

// If inside a parent class
$class_name = get_called_class();

// Or just inside the class
$class_name = get_class();

// Or straight get a class name
$class_name = MyCustomClass::class;

// Or, of course, a string
$class_name = 'App\Libs\MyCustomClass';

// Take the name down to the base name:
$class_name = end(explode('\\', $class_name)));

$inflector = InflectorFactory::create()->build();

$inflector->tableize($class_name); // my_custom_class

https://github.com/doctrine/inflector/blob/master/docs/en/index.rst

梦里°也失望 2024-08-23 19:31:02
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);
}
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);
}
最单纯的乌龟 2024-08-23 19:31:02

这里最糟糕的答案非常接近最好的答案(使用框架)。不,不要,只需查看源代码即可。看看一个完善的框架使用什么将是一个更可靠的方法(经过尝试和测试)。 Zend 框架有一些适合您需求的单词过滤器。 来源

这是我从源代码中改编的几种方法。

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

The worst answer on here was so close to being the best(use a framework). NO DON'T, just take a look at the source code. seeing what a well established framework uses would be a far more reliable approach(tried and tested). The Zend framework has some word filters which fit your needs. Source.

here is a couple of methods I adapted from the source.

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");
囍笑 2024-08-23 19:31:02

有一个提供此功能:

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

There is a library providing this functionality:

SnakeCaseFormatter::run('CamelCase'); // Output: "camel_case"
み格子的夏天 2024-08-23 19:31:02

如果您使用 Laravel 框架,则可以仅使用 snake_case() 方法。

If you use Laravel framework, you can use just snake_case() method.

看春风乍起 2024-08-23 19:31:02

如何在不使用正则表达式的情况下去骆驼化:

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

编辑:

在 2019 年我将如何做到这一点:

PHP 7.3 及之前:

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

}

以及 PHP 7.4+:

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

How to de-camelize without using 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;
}

An edit:

How would I do that in 2019:

PHP 7.3 and before:

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

}

And with PHP 7.4+:

function toSnakeCase($str, $glue = '_') {
    return ltrim(preg_replace_callback('/[A-Z]/', fn($matches) => $glue . strtolower($matches[0]), $str), $glue);
}
℉絮湮 2024-08-23 19:31:02

如果您使用 Laravel 框架,则存在更简单的内置方法:

$converted = Str::snake('fooBar'); // -> foo_bar

请参阅此处的文档:
https://laravel.com/docs/9.x/helpers#方法蛇形案例

If you're using the Laravel framework, a simpler built-in method exists:

$converted = Str::snake('fooBar'); // -> foo_bar

See documentation here:
https://laravel.com/docs/9.x/helpers#method-snake-case

许你一世情深 2024-08-23 19:31:02

开源 TurboCommons 库在 StringUtils 类中包含一个通用的 formatCase() 方法,它允许您将字符串转换为许多常见的大小写格式,例如 CamelCase、UpperCamelCase、LowerCamelCase、snake_case、Title Case 等。

https://github.com/edertone/TurboCommons

要使用它,请将 phar 文件导入到您的项目中和:

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

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

// will output 'camel_Case'

The open source TurboCommons library contains a general purpose formatCase() method inside the StringUtils class, which lets you convert a string to lots of common case formats, like CamelCase, UpperCamelCase, LowerCamelCase, snake_case, Title Case, and many more.

https://github.com/edertone/TurboCommons

To use it, import the phar file to your project and:

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

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

// will output 'camel_Case'
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文