2016-11-09 58 views
10

我有一個方法,現在,將轉換我的駱駝串蛇的情況下,但它的分解成preg_replace()三個電話:使用的preg_replace()轉換成首字母大寫snake_case

public function camelToUnderscore($string, $us = "-") 
{ 
    // insert hyphen between any letter and the beginning of a numeric chain 
    $string = preg_replace('/([a-z]+)([0-9]+)/i', '$1'.$us.'$2', $string); 
    // insert hyphen between any lower-to-upper-case letter chain 
    $string = preg_replace('/([a-z]+)([A-Z]+)/', '$1'.$us.'$2', $string); 
    // insert hyphen between the end of a numeric chain and the beginning of an alpha chain 
    $string = preg_replace('/([0-9]+)([a-z]+)/i', '$1'.$us.'$2', $string); 

    // Lowercase 
    $string = strtolower($string); 

    return $string; 
} 

我寫了測試,以驗證其

$test_values = [ 
    'foo'  => 'foo', 
    'fooBar' => 'foo-bar', 
    'foo123' => 'foo-123', 
    '123Foo' => '123-foo', 
    'fooBar123' => 'foo-bar-123', 
    'foo123Bar' => 'foo-123-bar', 
    '123FooBar' => '123-foo-bar', 
]; 

我不知道是否有減少我preg_replace()調用單行,這將給我相同的結果的方式:精度,並將其與輸入下面的數組(array('input' => 'output'))正常工作。有任何想法嗎?

注:Referring to this post,我的研究已經表明了我preg_replace()是正則表達式讓我幾乎結果我想要的,只是它不就foo123的工作,例如將其轉換爲foo-123

+1

@AdrienLeber閱讀我的問題的底線。它不是重複的。我閱讀了這篇文章,並沒有幫助我的問題。 – Matt

+0

對不起,我刪除了重複的標誌,並根據您在問題中提及的帖子上共享的內容發佈了新答案。 – JazZ

+0

@pete注意 – Matt

回答

12

您可以使用lookarounds做到這一切在一個單一的正則表達式:

function camelToUnderscore($string, $us = "-") { 
    return strtolower(preg_replace(
     '/(?<=\d)(?=[A-Za-z])|(?<=[A-Za-z])(?=\d)|(?<=[a-z])(?=[A-Z])/', $us, $string)); 
} 

RegEx Demo

Code Demo

正則表達式描述:

(?<=\d)(?=[A-Za-z]) # if previous position has a digit and next has a letter 
|     # OR 
(?<=[A-Za-z])(?=\d) # if previous position has a letter and next has a digit 
|     # OR 
(?<=[a-z])(?=[A-Z]) # if previous position has a lowercase and next has a uppercase letter 
+1

精彩的回答與解答。這正是我需要的。謝謝。 – Matt

1

從同事:

$string = preg_replace(array($pattern1, $pattern2), $us.'$1', $string);可能工作

我的解決辦法:

public function camelToUnderscore($string, $us = "-") 
{ 
    $patterns = [ 
     '/([a-z]+)([0-9]+)/i', 
     '/([a-z]+)([A-Z]+)/', 
     '/([0-9]+)([a-z]+)/i' 
    ]; 
    $string = preg_replace($patterns, '$1'.$us.'$2', $string); 

    // Lowercase 
    $string = strtolower($string); 

    return $string; 
} 
3

這是基於複製後我先前標記我的兩分錢。這裏接受的解決方案非常棒。我只是想嘗試什麼共同來解決這個問題:

function camelToUnderscore($string, $us = "-") { 
    return strtolower(preg_replace('/(?<!^)[A-Z]+|(?<!^|\d)[\d]+/', $us.'$0', $string)); 
} 

例子:

Array 
(
    [0] => foo 
    [1] => fooBar 
    [2] => foo123 
    [3] => 123Foo 
    [4] => fooBar123 
    [5] => foo123Bar 
    [6] => 123FooBar 
) 

foreach ($arr as $item) { 
    echo camelToUnderscore($item); 
    echo "\r\n"; 
} 

輸出:

foo 
foo-bar 
foo-123 
123-foo 
foo-bar-123 
foo-123-bar 
123-foo-bar 

說明:

(?<!^)[A-Z]+  // Match one or more Capital letter not at start of the string 
|     // OR 
(?<!^|\d)[\d]+ // Match one or more digit not at start of the string 

$us.'$0'   // Substitute the matching pattern(s) 

online regex

的問題是已經解決了,所以我不會說,我希望它能幫助,但也許有人會覺得這非常有用。


編輯

沒有與此正則表達式限制:其指示出來

foo123bar => foo-123bar 
fooBARFoo => foo-barfoo 

感謝@urban。下面是他與發佈關於這一問題的三種解決方案的測試鏈接:

three solutions demo

+0

您的解決方案與OP解決方案不同:它不考慮'foo123bar'的情況... 請參閱[code demo](http://ideone.com/Mr9wN5)OP解決方案與anubhava解決方案之間的區別和你的解決方案。 – Urban

+0

@urban'foo123bar'不是camelCase。但你是對的這個正則表達式有限制,它不是最好的解決方案......像'fooBARFoo'就會產生'foo-barfoo'。無論如何,這將用於基礎知識camelCase。我編輯答案。感謝您的反饋意見 ! – JazZ