如果我有:
$string = "PascalCase";
我需要
"pascal_case"
PHP是否为此提供功能?
如果我有:
$string = "PascalCase";
我需要
"pascal_case"
PHP是否为此提供功能?
Answers:
尝试以下尺寸:
$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
这实现了以下规则:
较短的解决方案:与编辑器类似,具有简化的正则表达式并解决了“底线下划线”问题:
$output = strtolower(preg_replace('/(?<!^)[A-Z]/', '_$0', $input));
请注意,类似的情况SimpleXML
将转换为simple_x_m_l
使用上述解决方案的情况。这也可以被认为是错误使用骆驼的大小写(正确SimpleXml
),而不是算法的错误,因为这样的情况总是模棱两可的-即使将大写字符组合成一个字符串(simple_xml
),这种算法在其他边缘情况下也总是会失败喜欢XMLHTMLConverter
或缩写附近的一个字母的单词,等等。如果您不介意(很少见)边缘情况并且想SimpleXML
正确处理,则可以使用一些更复杂的解决方案:
$output = ltrim(strtolower(preg_replace('/[A-Z]([A-Z](?![a-z]))*/', '_$0', $input)), '_');
简洁的解决方案,可以处理一些棘手的用例:
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
从Ruby String#camelize
和移植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);
}
上述解决方案可能遗漏的一个技巧是'e'修饰符,该修饰符导致preg_replace
将替换字符串评估为PHP代码。
e
标志preg_replace
。
^|
or strlen
。
该Symfony的串行组件具有CamelCaseToSnakeCaseNameConverter有两种方法normalize()
和denormalize()
。这些可以如下使用:
$nameConverter = new CamelCaseToSnakeCaseNameConverter();
echo $nameConverter->normalize('camelCase');
// outputs: camel_case
echo $nameConverter->denormalize('snake_case');
// outputs: snakeCase
$nameConverter->normalize('CamelCase')
输出_camel_case
。
这里的大多数解决方案都感到费力。这是我使用的:
$underscored = strtolower(
preg_replace(
["/([A-Z]+)/", "/_([A-Z]+)([A-Z][a-z])/"],
["_$1", "_$1_$2"],
lcfirst($camelCase)
)
);
“ CamelCASE”被转换为“ camel_case”
lcfirst($camelCase)
将降低第一个字符(避免将“ CamelCASE”转换后的输出以下划线开头)[A-Z]
找到大写字母+
会将每个连续的大写字母视为一个单词(避免将“ CamelCASE”转换为camel_C_A_S_E)ThoseSPECCases
-> those_spec_cases
而不是those_speccases
strtolower([…])
将输出变为小写lcfirst
功能$驼峰
ucfirst()
调用,此解决方案将意外地将以allcaps首个“单词”开头的输入字符串拆分。 USADollarSymbol
成为u_sa_dollar_symbol
演示,我不推荐这种解决方案,因为它必须使用正则表达式对输入字符串进行两次传递-这是未精炼模式的标志。
php没有为此afaik提供内置函数,但这是我使用的
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"
mb_strtolower
以及上的/u
选项成为unicode兼容preg_replace
。
您需要通过它运行一个匹配每个大写字母的正则表达式,除非它在开头,然后用下划线加上该字母替换。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
因为它不会丢失信息,并且向后转换将提供与我们开始时完全相同的字符串。即使您想以其他方式执行此操作,(?<!^)\p{Lu}\p{Ll}|(?<=\p{Ll})\p{Lu}
如果您不是正则表达式专家,也可以相对容易地为其编写正则表达式或带有两个正则表达式而无需后视。无需将其拆分为多个子字符串,更不用说决定使用just的方式strtolower
和lcfirst
位置了strtolower
。
如果您正在寻找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
);
}
根本不花哨,但简单快捷,如地狱般:
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
而不是$i++
使其速度更快;)
从“ 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, '_');
}
this-kind-of-output
可以在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);
}
所以这是一个单线:
strtolower(preg_replace('/(?|([a-z\d])([A-Z])|([^\^])([A-Z][a-z]))/', '$1_$2', $string));
g
向此正则表达式添加修饰符。
g
,对我来说很好用。
g
。但是我不记得我测试过的短语。
danielstjules / Stringy提供了一种将字符串从驼峰式转换为蛇形的方法。
s('TestUCase')->underscored(); // 'test_u_case'
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;
}
它的作用:如果发现给定字符串中至少有一个大写字母,它将使用正向搜索来搜索任何字符(.
),然后搜索大写字母((?=[A-Z])
)。然后,它将找到的字符替换为它的值,然后是separactor _
。
来自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, '-', '_'));
}
了解PHP,这将比此处给出的其他答案中进行的手动解析更快。缺点是您没有选择要用什么作为单词之间的分隔符,但这不是问题的一部分。
还要检查相关的rails源代码
请注意,这旨在与ASCII标识符一起使用。如果您需要使用ASCII范围以外的字符来执行此操作,请使用'/ u'修饰符preg_match
并使用mb_strtolower
。
Yii2具有不同的功能,可从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));
}
我有一个类似的问题,但找不到任何答案,无法满足如何将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));
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}
(或$name[$k]
)直接访问char ,这将使您的代码更长,但避免了将其与数组进行相互转换的大量开销。
这里最差的答案是如此接近最佳(使用框架)。不用,只看一下源代码。看到一个完善的框架使用什么将是一个更加可靠的方法(尝试并测试)。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");
如果使用Laravel框架,则可以只使用snake_case()方法。
这是较短的方法之一:
function camel_to_snake($input)
{
return strtolower(ltrim(preg_replace('/([A-Z])/', '_\\1', $input), '_'));
}
如何不使用正则表达式取消驼峰:
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年做到这一点:
function toSnakeCase($str, $glue = '_') {
return preg_replace_callback('/[A-Z]/', function ($matches) use ($glue) {
return $glue . strtolower($matches[0]);
}, $str);
}
当PHP 7.4发布时:
function toSnakeCase($str, $glue = '_') {
return preg_replace_callback('/[A-Z]/', fn($matches) => $glue . strtolower($matches[0]), $str);
}
使用Zend Word Filters的Filter类很容易:
<?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
容易>>>容易
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
容易>>>容易
HTML >>> HTML
simpleXML >>> simple_xml
PDFLoad >>> pdf_load
startMIDDLELast >>> start_middle_last
AString >>> a_string
Some4Numbers234 >>> some4_numbers234
TEST123String >>> test123_string
开源的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'
$str = 'FooBarBaz';
return strtolower(preg_replace('~(?<=\\w)([A-Z])~', '_$1', $str)); // foo_bar_baz
如果您可以从以下内容开始:
$string = 'Camel_Case'; // underscore or any other separator...
然后,您可以仅使用以下方法转换为两种情况:
$pascal = str_replace("_", "", $string);
$snake = strtolower($string);
或任何其他情况:
$capitalized = str_replace("_", " ", $string); // Camel Case
$constant = strtoupper($string); // CAMEL_CASE
$train = str_replace("_", "-", $snake); // camel-case