سؤال

لو كان لدي:

$string = "PascalCase";

احتاج

"pascal_case"

هل تقدم PHP وظيفة لهذا الغرض؟

هل كانت مفيدة؟

المحلول

جرب هذا على الحجم:

$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. يمكن أن يتبع تسلسل يبدأ بحرف كبير إما:
    • أحرف وأرقام كبيرة واحدة أو أكثر (تليها إما نهاية السلسلة أو حرفًا كبيرًا متبوعًا بحرف صغير أو رقم ، أي بداية التسلسل التالي) ؛ أو
    • أحرف أو أرقام صغيرة أو أكثر.

نصائح أخرى

حل أقصر: على غرار محرر واحد مع تعبير منتظم مبسط وإصلاح مشكلة "inderscore":

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

PHP Demo | Regex Demo


لاحظ أن حالات مثل 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 | Regex Demo

حل موجز ويمكنه التعامل مع بعض حالات الاستخدام الصعبة:

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

نقل من روبي 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.

ال مكون Symfony Serializer لديه camelcasetosnakeCasenameConverter التي لها طريقتان normalize() و denormalize(). يمكن استخدامها على النحو التالي:

$nameConverter = new CamelCaseToSnakeCaseNameConverter();

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

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

معظم الحلول هنا تشعر بالقلق. هذا ما أستخدمه:

$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([…]) يحوّل الإخراج إلى الحالات السفلية

لا يقدم 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"
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_áááá_őőőő

إذا كنت تبحث عن إصدار 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

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

يمكن العثور على نسخة لا تستخدم Regex في 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));

Danielstjules/Stringy يثبت طريقة لتحويل السلسلة من Camelcase إلى SnakeCase.

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

ما يفعل lookahead إيجابية للبحث عن أي حرف (.) تليها رسالة رأسمالية ((?=[A-Z])). ثم يحل محل الحرف الذي تم العثور عليه بقيمة تليها عامل الانفصال _.

سيكون المنفذ المباشر من القضبان (ناقص معالجة خاصة به لـ :: أو الاختصارات)

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 ، سيكون هذا أسرع من التحليل اليدوي الذي يحدث في إجابات أخرى مقدمة هنا. العيب هو أنه لا يمكنك اختيار ما يجب استخدامه كفاصل بين الكلمات ، لكن هذا لم يكن جزءًا من السؤال.

تحقق أيضا من رمز مصدر القضبان ذات الصلة

لاحظ أن هذا مخصص للاستخدام مع معرفات ASCII. إذا كنت بحاجة إلى القيام بذلك باستخدام أحرف خارج نطاق ASCII ، فاستخدم معدل "/U" preg_matchوالاستخدام mb_strtolower.

إليكم مساهمتي في سؤال عمره ست سنوات مع الله يعرف عدد الإجابات ...

سيقوم بتحويل جميع الكلمات في السلسلة المقدمة الموجودة في Camelcase إلى SnakeCase. على سبيل المثال ، "سيتم تحويل" superspecialawesome وأيضًا fizbuzz καικάτιακόμα "إلى" super_special وأيضًا fizz_buzz και_κάτι_ακόμα ".

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

yii2 لديك وظيفة مختلفة لجعل كلمة snake_case من 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));
    }
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);
}

هناك مكتبة توفير هذه الوظيفة:

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

إذا كنت تستخدم Laravel Framework ، يمكنك استخدام فقط snake_case () طريقة.

$str = 'FooBarBaz';

return strtolower(preg_replace('~(?<=\\w)([A-Z])~', '_$1', $str)); // foo_bar_baz

هذه واحدة من الطرق الأقصر:

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

كيفية إلغاء التمييز دون استخدام 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;
}

تحرير:

كيف أفعل ذلك في عام 2019:

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

وعندما سيتم إصدار 7.4 PHP:

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

حل قصير:

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

من السهل استخدام فئات التصفية من 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;
    }
}

------

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

كانت أسوأ إجابة هنا قريبة جدًا من كونها الأفضل (استخدم إطار عمل). لا لا ، فقط ألق نظرة على رمز المصدر. إن رؤية ما تستخدمه الإطار الراسخ سيكون نهجًا أكثر موثوقية (تم تجربته واختباره). يحتوي Zend Framework على بعض مرشحات الكلمات التي تناسب احتياجاتك. مصدر.

فيما يلي بعض الطرق التي قمت بتكييفها من المصدر.

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

تحتوي مكتبة TurboCommons مفتوحة المصدر على طريقة تنسيق للأغراض العامة () داخل فئة StringUtils ، والتي تتيح لك تحويل سلسلة إلى الكثير من تنسيقات الحالات الشائعة ، مثل Camelcase و UperCamelcase و LowerCamelcase و Snake_Case و 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'

لقد واجهت مشكلة مماثلة ولكن لم أتمكن _ للأسماء مع السطحية ، أو جميع caps اختصارات.

المشكلة مثل المتابعة:

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

الحل الذي كتبته هو استدعاء وظيفتين بسيطتين ، وأحرف صغيرة وبحث واستبدل لأحرف أقدم صغيرة متتالية:

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

إذا تمكنت من البدء بـ:

$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
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top