2

I have camel cased strings like this:

"numberOf40"
"numberOf40hc"

How can I split it like this?

["number", "Of", "40"]
["number", "Of", "40hc"]

I am using humps to decamelize keys so I can only pass a split regex as option. I am looking for an answer that only uses split function.

My best attempts:

const a = "numberOf40hc"

a.split(/(?=[A-Z0-9])/)
// ["number", "Of", "4", "0hc"]

a.split(/(?=[A-Z])|[^0-9](?=[0-9])/)
// ["number", "O", "40hc"]

Also I don't understand why the f is omitted in my last attempt.

adesurirey
  • 2,549
  • 2
  • 16
  • 36

3 Answers3

3

You don't get the f in you last attempt (?=[A-Z])|[^0-9](?=[0-9]) as this part of the last pattern [^0-9] matches a single char other than a digit and will split on that char.

You could also match instead of split

const regex = /[A-Z]?[a-z]+|\d+[a-z]*/g;

[
  "numberOf40",
  "numberOf40hc"
].forEach(s => console.log(Array.from(s.matchAll(regex), m => m[0])));

Using split only, you could use lookarounds with a lookbehind which is gaining more browser support.

const regex = /(?=[A-Z])|(?<=[a-z])(?=\d)/g;

[
  "numberOf40",
  "numberOf40hc"
].forEach(s => console.log(s.split(regex)));
The fourth bird
  • 154,723
  • 16
  • 55
  • 70
2

const a = "numberOf40hc"

let b = a.split(/(\d+[a-z]*|[A-Z][a-z]*)/).filter(a => a);

console.log(b);

The .filter(a => a) is necessary because split, returns both the left and right side of a matched delimter. E.g. 'a.'.split('.') returns both the left (i.e. 'a') and right (i.e. '') side of '.'.

Per your update regarding the need for compatibility with humps, it seems humps supports customizing the handler:

const humps = require('humps');

let myObj = {numberOf40hc: 'value'};

let decamelizedObj = humps.decamelizeKeys(myObj, key =>
        key.split(/(\d+[a-z]*|[A-Z][a-z]*)/).filter(a => a).join('_'));

console.log(decamelizedObj);
junvar
  • 11,151
  • 2
  • 30
  • 46
  • 1
    He wants the last element to be `40hc` not `hc` – Hogan Mar 15 '21 at 16:05
  • Thank you but I am using Humps.js to decamelize keys so I can only pass a `split` regex. I am looking for an answer that only uses `split`. I edited my question to be clearer. – adesurirey Mar 15 '21 at 16:12
1

Try this:

const splitStr = (str='') =>
  str.split(/([A-Z][a-z]+)/).filter(e => e);
console.log( splitStr("numberOf40") );
console.log( splitStr("numberOf40hc") );
Majed Badawi
  • 27,616
  • 4
  • 25
  • 48
  • Thank you but I am using Humps.js to decamelize keys so I can only pass a `split` regex. I am looking for an answer that only uses `split`. I edited my question to be clearer. – adesurirey Mar 15 '21 at 16:12