camelCase to dash - two capitals next to each other
Asked Answered
I

4

18

I'm using this function to convert CamelCase to dashed string:

function camel2dashed($className) {
    return strtolower(preg_replace('/([^A-Z-])([A-Z])/', '$1-$2', $className));
}

it kinda works but theres problem when I have for ex. this string: getADog. It returns get-adog but I want get-a-dog

how should I change my code? Thanks

Idea answered 8/5, 2012 at 23:7 Comment(4)
Have you considered if you wanted two capital letters next to each other? For example, companyHQ for company headquarters? You wouldn't want company-h-q, right?Ascending
in this case you're right but it won't happen. thanksIdea
This isn't camelCase. It's PascalCase btw.Count
Terms: camelCase versus PascalCase versus StudlyCase versus snake_case versus kebab-caseCommemorative
T
38

Use a lookahead assertion:

function camel2dashed($className) {
    return strtolower(preg_replace('/([a-zA-Z])(?=[A-Z])/', '$1-', $className));
}

See it working online: ideone

Traffic answered 8/5, 2012 at 23:8 Comment(0)
P
8

You don't need a lookahead assertion to do this if you know that your string doesn't start with an upper-case letter, you can just insert a hyphen before every upper-case letter like this:

function camel2dashed($className) {
    return strtolower(preg_replace('/([A-Z])/', '-$1', $className));
}

This still won't handle cases like @sfjedi's "companyHQ" -> "company-hq". For that you'd have to explicitly test for permitted capitalized substrings that shouldn't be split, or specify some generic rules (e.g. don't prepend hyphen before last character).

You can find some more sophisticated alternatives in the answers to this virtual duplicate question.

Perr answered 8/5, 2012 at 23:28 Comment(0)
R
0
function camel2dash($name) {
   return ltrim(strtolower(preg_replace('/[A-Z]([A-Z](?![a-z]))*/', '-$0', $name)), '-');
}

Handles hopefully all edge cases:

SomeOfTheWords → some-of-the-words
getADog → get-a-dog
ADog → a-dog
aDog → a-dog
XML → xml
SimpleXMLReader → simple-xml-reader
Reclamation answered 21/6, 2022 at 13:34 Comment(0)
C
0

Your camelCase to kebab-case pattern doesn't need to capture anything or use a backreference in the replacement.

Code: (Demo)

$className = 'getADog';
echo strtolower(preg_replace('/[a-zA-Z]\K(?=[A-Z])/', '-', $className));
// get-a-dog

For a regex that is more robust and will handle camelCase and StudlyCase and will correctly handle acronyms and numeric strings, try the following. (Demo)

(?>               #start atomic group (use first qualifying branch)
   [A-Z]?[a-z]+   #zero or one upper followed by one or more lowers
   |              #OR
   [A-Z]+         #one or more uppers
   (?=            #start lookahead without consuming characters
      [A-Z][a-z]  #one upper followed by one lower
      |           #OR
      [^A-Za-z]   #one non-letter
   )              #end lookahead
   |              #OR
   [^A-Za-z]+     #one or more non-letters
)                 #end atomic group
\K                #forget any consumed matched characters so far
(?!$)             #position must not be the end of the string

Code: (Demo)

$tests = [
    'getADogThenROCKInTheUSA',
    'SomeOfTheWords',
    'getADog',
    'ADog',
    'aDog',
    'XML',
    'SimpleXMLReader',
    'FREE4NOW',
    '123ABC',
    'DEF456',
    'ghi789',
    'wtf666Omg',
    'PHP8Point3',
    
];
foreach ($tests as $test) {
    printf(
        "%25s => %s\n",
        $test,
        strtolower(
            preg_replace(
                '/(?>[A-Z]?[a-z]+|[A-Z]+(?=[A-Z][a-z]|[^A-Za-z])|[^A-Za-z]+)\K(?!$)/',
                '-',
                $test
            )
        )
    );
}

Output:

  getADogThenROCKInTheUSA => get-a-dog-then-rock-in-the-usa
           SomeOfTheWords => some-of-the-words
                  getADog => get-a-dog
                     ADog => a-dog
                     aDog => a-dog
                      XML => xml
          SimpleXMLReader => simple-xml-reader
                 FREE4NOW => free-4-now
                   123ABC => 123-abc
                   DEF456 => def-456
                   ghi789 => ghi-789
                wtf666Omg => wtf-666-omg
               PHP8Point3 => php-8-point-3
Commemorative answered 16/2 at 7:56 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.