2016-11-09 57 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