Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert different strings to snake_case in Javascript

I know that we have a question similar to this but not quite the same. I'm trying to make my function work which takes in a string as an argument and converts it to snake_case . It works most of the time with all the fancy !?<>= characters but there is one case that it can't convert and its camelCase .

It fails when I'm passing strings like snakeCase. It returns snakecase instead of snake_case.

I tried to implement it but I ended up just messing it up even more..

Can I have some help please?

my code:

const snakeCase = string => {
    string = string.replace(/\W+/g, " ").toLowerCase().split(' ').join('_');

    if (string.charAt(string.length - 1) === '_') {
        return string.substring(0, string.length - 1);
    }

    return string;
}
like image 405
dragi Avatar asked Nov 28 '22 21:11

dragi


2 Answers

You need to be able to detect the points at which an upper-case letter is in the string following another letter (that is, not following a space). You can do this with a regular expression, before you call toLowerCase on the input string:

\B(?=[A-Z])

In other words, a non-word boundary, followed by an upper case character. Split on either the above, or on a literal space, then .map the resulting array to lower case, and then you can join by underscores:

const snakeCase = string => {
    return string.replace(/\W+/g, " ")
      .split(/ |\B(?=[A-Z])/)
      .map(word => word.toLowerCase())
      .join('_');
};

console.log(snakeCase('snakeCase'));
like image 57
CertainPerformance Avatar answered Dec 06 '22 09:12

CertainPerformance


Let's try that again Stan... this should do snake_case while realising that CamelCASECapitals = camel_case_capitals. It's actually the accept answer with a pre-filter.

let splitCaps = string => string
    .replace(/([a-z])([A-Z]+)/g, (m, s1, s2) => s1 + ' ' + s2)
    .replace(/([A-Z])([A-Z]+)([^a-zA-Z0-9]*)$/, (m, s1, s2, s3) => s1 + s2.toLowerCase() + s3)
    .replace(/([A-Z]+)([A-Z][a-z])/g, 
        (m, s1, s2) => s1.toLowerCase() + ' ' + s2);
let snakeCase = string =>
    splitCaps(string)
        .replace(/\W+/g, " ")
        .split(/ |\B(?=[A-Z])/)
        .map(word => word.toLowerCase())
        .join('_');
> a = ['CamelCASERules', 'IndexID', 'CamelCASE', 'aID', 
       'theIDForUSGovAndDOD', 'TheID_', '_IDOne']

> _.map(a, snakeCase)

['camel_case_rules', 'index_id', 'camel_case', 'a_id', 'the_id_for_us_gov_and_dod', 
 'the_id_', '_id_one']

// And for the curious, here's the output from the pre-filter:

> _.map(a, splitCaps)

['Camel case Rules', 'Index Id', 'Camel Case', 'a Id', 'the id For us Gov And Dod', 
 'The Id_', '_id One']
like image 36
Orwellophile Avatar answered Dec 06 '22 10:12

Orwellophile