2016-11-09 4 views
10

ich eine Methode müssen snake_case dass jetzt mein Kamel Fall Strings Schlange Fall konvertieren, aber es ist in drei Anrufe von preg_replace() gebrochen:Mit preg_replace() Camelcase konvertieren

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

I Tests schrieb seine überprüfen Genauigkeit, und es funktioniert mit der folgenden Anordnung von Eingängen (array('input' => 'output')):

$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', 
]; 

ich frage mich, ob es eine Möglichkeit gibt, meine preg_replace() Anrufe an eine einzige Leitung zu reduzieren, die mir das gleiche Ergebnis geben wird. Irgendwelche Ideen?

HINWEIS: Referring to this post hat meine Forschung mich eine preg_replace() regex gezeigt, die mich fast das Ergebnis Ich möchte bekommt, außer es nicht auf das Beispiel von foo123 es foo-123 zu konvertieren funktioniert.

+1

@AdrienLeber die untere Zeile meiner Frage zu lesen. Es ist kein Duplikat. Ich habe diesen Beitrag gelesen und es hat mir bei meiner Frage nicht geholfen. – Matt

+0

Entschuldigung, ich habe die Duplikatmarkierung gelöscht und eine neue Antwort veröffentlicht, basierend darauf, was auf dem Beitrag geteilt wurde, auf den Sie in Ihrer Frage verweisen. – JazZ

+0

@pete aufpassen – Matt

Antwort

12

können Sie lookarounds verwenden all dies in einem einzigen Regex zu tun:

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

RegEx Beschreibung:

(?<=\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

Wunderbare Antwort und Erklärung. Genau das habe ich gebraucht. Vielen Dank. – Matt

1

Von einem Kollegen:

$string = preg_replace(array($pattern1, $pattern2), $us.'$1', $string); funktionieren könnte

Meine Lösung:

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

Hier ist meine zwei Cent basiert ich auf dem duplizierten Post früher Liste steht. Die akzeptierte Lösung ist großartig. Ich wollte nur versuchen, es mit zu lösen, was geteilt wurde:

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

Beispiel:

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

Ausgang:

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

Erläuterung:

(?<!^)[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

Die Frage gelöst ist bereits so werde ich nicht sagen, dass ich hoffe, es hilft, aber vielleicht wird jemand diese nützlich zu finden.


EDIT

Es gibt Grenzen dieser regex:

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

Dank für spitze es heraus @urban. Hier ist seine Verbindung mit Tests mit den drei Lösungen zu dieser Frage geschrieben:

three solutions demo

+0

Ihre Lösung unterscheidet sich von der OP-Lösung: Sie berücksichtigt nicht den Fall 'foo123bar' ... Siehe [Code-Demo] (http://ideone.com/Mr9wN5) den Unterschied zwischen OP-Lösung, Anubhava-Lösung und deine Lösung. – Urban

+0

@urban 'foo123bar' ist nicht camelCase. Aber du hast recht, es gibt Grenzen mit dieser Regex und es ist nicht die beste Lösung ... Etwas wie 'fooBARFoo' wird' foo-barfoo' produzieren. Wie auch immer, das wird für die Grundlagen von camelCase. Ich bearbeite die Antwort. Vielen Dank für Ihr Feedback ! – JazZ