Articles

cf-HumanNameParser: Parsing People's Names in CFML Without a Jar

cf-HumanNameParser: Split a person's name into its parts. One CFC, no jar.
November 12, 2026

I have a ColdFusion script that splits full names into first, last, salutation, and so on. It calls HumanNameParser.java 0.1 on ColdFusion 2016. I went to update the jar to 0.3, dropped in the new file, and got an error that the Name class doesn't exist.

My first guess was a bug in the updated library... and I was wrong. The jar I downloaded was named correctly, but from a different project.

Same package, different project

There are two projects hosted on Maven called human-name-parser. One is com.tupilabs, the original Java port by Bruno P. Kinoshita. The other is com.github.steveash.hnp, a fork. The fork keeps the com.tupilabs.human_name_parser package name, so the class paths look right, but the API is different. There's no Name class, you call parse() on a HumanNameParser and then convert the results with toSegmented(). It additionally requires Guava 19+ as a dependency, and I couldn't find it anywhere in our ColdFusion 2016's lib folder. The links saved in my own script comments incorrectly pointed at the fork.

After changing out the right 0.3 jar are restarting the ColdFusion service, things worked again. But the Java source is small: seven regular expressions applied in order, each one chopping its match off the string. This analysis seemed like a poor excuse to keep managing a jar, so I ported it to CFML. The result is one CFC that runs on Adobe ColdFusion 2016+, Lucee 5+, and BoxLang.

parser = new HumanNameParser();
parts  = parser.parse( "Dr. B. William Carlos ""Billy"" von Williams III,PHD" );

// parts.salutation   Dr.
// parts.leadingInit  B.
// parts.first        William
// parts.nicknames    Billy
// parts.middle       Carlos
// parts.last         von Williams
// parts.suffix       III
// parts.postnominal  PHD

It handles "Last, First" order, nicknames in quotes or parentheses, compound last names like "van der Sar" and "Ortega y Gasset", and you can add your own salutations, suffixes, prefixes, and postnominals. I needed that last one for audiology credentials:

parser = new HumanNameParser( extraPostnominals = [ "Au\.D\.", "CCC-A" ] );

Checking a port against the original

I didn't want "it looks about right." My test runner fed 392 names through the CFC and compared every field against what the real 0.3 jar returned for the same name, including the 13 names where the jar was throwing an error. A small Java program generates the expected results file, so the jar served as the judge and not my reading of the source. That's a total of 3,859 checks and they pass on ColdFusion 2016.0.17, Lucee 5.4.8.2, and BoxLang 1.19.0.

While comparing results, one name disagreed: "etna ubel", where the "u" has an umlaut. The jar said the last name was "bel" and the middle name was the lone u-umlaut. The CFC kept the last name in one piece.

While both were running the same regex, the difference came down to the JVM. I had generated the expected results on Java 25, and the CFC was running on ColdFusion 2016's much older Java. Starting with Java 19, \b in a regular expression only treats ASCII letters as word characters, so on a new JVM there's a word boundary between the u-umlaut and the "b" that didn't exist before. The Java library was giving different answers for that name depending on which version of Java was used. The CFC now asks for a Unicode-aware boundary with (?U:\b), so it returns the whole last name everywhere. If you have Java regexes with \b and data with accented letters, this issue is worth reviewing before your next JVM upgrade.

Three incorrectly parsed names

My test list had 81 names with known answers, and three were failing: "Jason Senior", "Bill Junior", and "Mr. Van Truong". The jar was failing on them too.

"Senior" and "Junior" are part of the suffix list. The parser strips the suffix first, has one word left, and gives up because there's no last name. "Van" is in the list of last-name prefixes (as in van Gogh), so "Van Truong" becomes the whole last name and nothing is left for a first name.

That second one is less rare than it looks. "Ben", "San", "Le", "La", and "Del" are on the prefix list too, which means "Dr. Ben Carson" fails the same way.

The CFC now has a fallback for each. A spelled-out suffix that leaves no last name becomes the last name, and a prefix that leaves no first name becomes the first name. Both rules only apply to names that would otherwise throw, so nothing that parsed before changes and the tests run all 379 parseable names in both modes as confirmation. If you want the jar's exact behavior, new HumanNameParser( strict = true ) disabled this behavior.

What it won't do

It's regexes, with no dictionary of names behind them. "Mary Ben Smith" comes back with the last name "Ben Smith", because the rule that gets "Ludwig van Beethoven" right can't tell the difference. A name followed by several comma-separated credentials gets rejected, so I prefer to manually strip those before parsing on projects that require it. Capitalization is also left up to the original string.

One BoxLang note for anyone wanting to port their own code: an optional argument you didn't pass still shows up in structKeyExists( arguments, "name" ) there, with a null value (this was BoxLang 1.19 without the bx-compat-cfml module). isNull( arguments.name ) is the recommended approach and gives the same answer on all three engines.

Source Code

https://github.com/JamoCA/cf-HumanNameParser

MIT licensed, same as the Java and PHP libraries it comes from. Credit for the parsing approach goes to Jason Priem's HumanNameParser.php and Bruno P. Kinoshita's Java port.