I was trying to make a RegExp with the following expected results:
Input: James Cameron
Expected: JC
Input: James cameron
Expected: JC
Input: James
Expected: JA
Input: James Francis Cameron
Expected: JF
I gave up and ended using the following JS code:
function initials(name) {
return name.toUpperCase().split(/\s+/g).map((s, _i, arr) => (arr.length > 1 ? s[0] : s[0] + s[1])).reduce((a, b) => a + b).substring(0,2);
}
Making two separated regular expressions was also easy (for example: name.replace(/^\s*([a-z]).+?\s+([a-z]).*$/, '$1$2')
)
However i understand it should be a way to fulfill this using only one RegExp.
UPDATE: Later on, I had one more test-string. The accepted answer didn't worked for it: James Francis Cameron
as the expected result was JF
.
I solved it by using the following regex, and replace
with $1$2$3
:
^\s*(\S)(?:.+?\s(\S)|(\S)).*$
You may use
.replace(/^(\S{2})\S*$|(?:^|\s*)(\S)\S*\s*/g, '$1$2').toUpperCase()
See the regex demo and the JavaScript demo:
const initials = (name, regex) => name.replace(regex, '$1$2').toUpperCase()
const arr = ['Elon Musk','Elon musk','Elon'];
const rex = /^(\S{2})\S*$|(?:^|\s*)(\S)\S*\s*/g;
arr.forEach( x => console.log(x, "=>", initials(x, rex)) );
Regex details
^(\S{2})\S*$
- start of string (^
), any 2 non-whitespace characters captured in Group 1 (see (\S{2})
, later referenced to with $1
), and then any 0 or more non-whitespace chars (\S*
) up to the end of string ($
)|
- or(?:^|\s*)(\S)\S*\s*
- start of string or 0 or more whitespaces ((?:^|\s*)
), then one non-whitespace char captured into Group 2 (see (\S)
, later referenced with $2
), and then 0+ non-whitespaces followed with 0+ whitespaces.