typescript
50 lines · 9 steps
Parsing human names into structured parts
A name splitter that handles suffixes, prefixes, and 'Last, First' ordering before carving out first/middle/last.
Explained by
highlit
1interface ParsedName {
2 first: string;
3 middle: string;
4 last: string;
5 suffix: string;
6}
7
8const SUFFIXES = new Set([
9 "jr", "sr", "ii", "iii", "iv", "v", "phd", "md", "esq",
10]);
11
12const PREFIXES = new Set([
13 "mr", "mrs", "ms", "miss", "dr", "prof", "rev", "sir",
14]);
15
16const normalizeSuffix = (token: string): string =>
17 token.replace(/\./g, "").toLowerCase();
18
19export function splitName(fullName: string): ParsedName {
20 const empty: ParsedName = { first: "", middle: "", last: "", suffix: "" };
21
22 if (fullName.includes(",")) {
23 const [lastPart, ...rest] = fullName.split(",");
24 fullName = `${rest.join(" ")} ${lastPart}`;
25 }
26
27 const tokens = fullName.trim().split(/\s+/).filter(Boolean);
28 if (tokens.length === 0) return empty;
29
30 let suffix = "";
31 const tail = tokens[tokens.length - 1];
32 if (tokens.length > 1 && SUFFIXES.has(normalizeSuffix(tail))) {
33 suffix = tokens.pop()!;
34 }
35
36 if (tokens.length > 1 && PREFIXES.has(normalizeSuffix(tokens[0]))) {
37 tokens.shift();
38 }
39
40 if (tokens.length === 0) return { ...empty, suffix };
41 if (tokens.length === 1) {
42 return { first: tokens[0], middle: "", last: "", suffix };
43 }
44
45 const first = tokens.shift()!;
46 const last = tokens.pop()!;
47 const middle = tokens.join(" ");
48
49 return { first, middle, last, suffix };
50}
01 / 01
STEP 01
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1Normalizing tokens against known sets lets you detect suffixes and titles regardless of punctuation or casing.
- 2Peeling recognized pieces off the ends first leaves a clean core to split into first/middle/last.
- 3Guarding each length boundary prevents the parser from crashing on empty or single-token input.
Related explainers
typescript
import { registerLocaleData } from '@angular/common'; import localeFr from '@angular/common/locales/fr'; import localeFrExtra from '@angular/common/locales/extra/fr'; import localeDe from '@angular/common/locales/de';
Locale-aware bootstrapping in Angular
i18n
localization
dependency-injection
Intermediate
8 steps
php
<?php class NameParser {
Parsing a full name into components in PHP
string-parsing
arrays
normalization
Intermediate
8 steps
typescript
import { Module } from '@nestjs/common'; import { ConfigModule } from '@nestjs/config'; import * as Joi from 'joi';
Validating env config at boot in NestJS
configuration
schema-validation
environment-variables
Intermediate
8 steps
ruby
class UserAgentParser BROWSERS = [ [/Edg\/([\d.]+)/, "Edge"], [/OPR\/([\d.]+)/, "Opera"],
Parsing user-agent strings in Ruby
regex
pattern-matching
lookup-tables
Intermediate
8 steps
javascript
function evaluate(expression) { const tokens = tokenize(expression); let pos = 0;
Building a recursive descent calculator
parsing
recursion
operator-precedence
Intermediate
8 steps
typescript
import { Inject, Injectable, Logger } from '@nestjs/common'; import { CACHE_MANAGER } from '@nestjs/cache-manager'; import { Cache } from 'cache-manager'; import { InjectRepository } from '@nestjs/typeorm';
A cache-aside country lookup in NestJS
cache-aside
dependency-injection
batch-lookup
Intermediate
8 steps
Share this explainer
Here's the card — post it anywhere.
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code
Embed this explainer
Drop the interactive walkthrough into a blog or docs. Views never cost a credit.
<iframe src="https://highlit.co/explainers/parsing-human-names-into-structured-parts-explained-typescript-3b2e/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.