Skip to content

Commit

Permalink
Add support for initial names like JJ Abrams and JD Salinger
Browse files Browse the repository at this point in the history
  • Loading branch information
jdhartley committed Feb 2, 2022
1 parent 461904b commit 8370390
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 2 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ Formatter::nameCase("VON STREIT"); // => von Streit
Formatter::nameCase("AP LLWYD DAFYDD"); // => ap Llwyd Dafydd
Formatter::nameCase("HENRY VIII"); // => Henry VIII
Formatter::nameCase("VAN DYKE"); // => van Dyke
Formatter::nameCase("JJ ABRAMS"); // => JJ Abrams
Formatter::nameCase("PRINCE PHILIP, DUKE OF EDINBURGH"); // => Prince Philip, Duke of Edinburgh

// Or as an instance
Expand Down
35 changes: 35 additions & 0 deletions src/Formatter.php
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,19 @@ class Formatter
// Excluded post-nominals
private static $postNominalsExcluded = [];

// Most two-letter words with no vowels should be kept in all caps as initials
private const INITIAL_NAME_REGEX = '\b(Aj|[bcdfghjklmnpqrstvwxyzBCDFGHJKLMNPQRSTVWXYZ]{2})\s';
private const INITIAL_NAME_EXCEPTIONS = [
'Mr',
'Dr',
'St',
'Jr',
'Sr',
// FIXME: These collide with POST_NOMINALS
// 'Ms',
// 'Lt',
];

// Lowercase words
private const LOWER_CASE_WORDS = ['The', 'Of', 'And'];

Expand Down Expand Up @@ -169,6 +182,8 @@ public static function nameCase($name = '', array $options = []): string
$name = mb_ereg_replace($pattern, $replacement, $name);
}

$name = self::correctInitialNames($name);

$name = self::correctLowerCaseWords($name);

return self::processOptions($name);
Expand Down Expand Up @@ -329,6 +344,26 @@ private static function fixConjunction(string $name): string
return $name;
}

/**
* Correct capitalization of initial names like JJ and TJ.
*
* @param string $name
*
* @return string
*/
private static function correctInitialNames(string $name): string
{
return mb_ereg_replace_callback(self::INITIAL_NAME_REGEX, function ($matches) {
$match = $matches[0];

if (in_array($matches[1], self::INITIAL_NAME_EXCEPTIONS)) {
return $match;
}

return mb_strtoupper($match);
}, $name);
}

/**
* Correct lower-case words of titles.
*
Expand Down
19 changes: 17 additions & 2 deletions tests/NameCaseTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,20 @@ final class NameCaseTest extends TestCase
"Charles II", "Fred XLIX",
];

private $initialNames = [
// Two letter initials names should remain capital with and without periods
"JJ Abrams", "JD Salinger", "AJ Michalka",
"J. F. Kennedy", "J.F. Kennedy",
// Except for some specifics
"Mr Smith",
"Dr Martin Luther King Jr",
"St Patrick",
"Martin Luther King Sr",
// FIXME: These collide with POST_NOMINALS
// "Ms Smith",
// "Lt Worf",
];

/** Test numbers. */
public function testNumbersAreUnaffected(): void
{
Expand Down Expand Up @@ -107,8 +121,9 @@ public function testRomanNumerals(): void
/** Test initials */
public function testInitials(): void
{
$this->assertEquals('J. F. Kennedy', Formatter::nameCase(mb_strtolower('J. F. Kennedy')));
$this->assertEquals('J.F. Kennedy', Formatter::nameCase(mb_strtolower('J.F. Kennedy')));
foreach ($this->initialNames as $name) {
$this->assertEquals($name, Formatter::nameCase(mb_strtolower($name)));
}
}

private $programmers = [
Expand Down

0 comments on commit 8370390

Please sign in to comment.