Skip to content

Commit b79f720

Browse files
authored
Added Hyperf\Stringable\Str::apa() method (#6576)
1 parent 1046533 commit b79f720

File tree

3 files changed

+94
-0
lines changed

3 files changed

+94
-0
lines changed

src/Str.php

+50
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,56 @@ public static function afterLast($subject, $search)
7878
return substr($subject, $position + strlen($search));
7979
}
8080

81+
/**
82+
* Convert the given string to APA-style title case.
83+
*
84+
* See: https://apastyle.apa.org/style-grammar-guidelines/capitalization/title-case
85+
*
86+
* @param string $value
87+
* @return string
88+
*/
89+
public static function apa($value)
90+
{
91+
if (trim($value) === '') {
92+
return $value;
93+
}
94+
95+
$minorWords = [
96+
'and', 'as', 'but', 'for', 'if', 'nor', 'or', 'so', 'yet', 'a', 'an',
97+
'the', 'at', 'by', 'for', 'in', 'of', 'off', 'on', 'per', 'to', 'up', 'via',
98+
];
99+
100+
$endPunctuation = ['.', '!', '?', ':', '', ','];
101+
102+
$words = preg_split('/\s+/', $value, -1, PREG_SPLIT_NO_EMPTY);
103+
104+
$words[0] = ucfirst(mb_strtolower($words[0]));
105+
106+
for ($i = 0; $i < count($words); ++$i) {
107+
$lowercaseWord = mb_strtolower($words[$i]);
108+
109+
if (str_contains($lowercaseWord, '-')) {
110+
$hyphenatedWords = explode('-', $lowercaseWord);
111+
112+
$hyphenatedWords = array_map(function ($part) use ($minorWords) {
113+
return (in_array($part, $minorWords) && mb_strlen($part) <= 3) ? $part : ucfirst($part);
114+
}, $hyphenatedWords);
115+
116+
$words[$i] = implode('-', $hyphenatedWords);
117+
} else {
118+
if (in_array($lowercaseWord, $minorWords)
119+
&& mb_strlen($lowercaseWord) <= 3
120+
&& ! ($i === 0 || in_array(mb_substr($words[$i - 1], -1), $endPunctuation))) {
121+
$words[$i] = $lowercaseWord;
122+
} else {
123+
$words[$i] = ucfirst($lowercaseWord);
124+
}
125+
}
126+
}
127+
128+
return implode(' ', $words);
129+
}
130+
81131
/**
82132
* Transliterate a UTF-8 value to ASCII.
83133
*

src/Stringable.php

+10
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,16 @@ public function afterLast($search)
8686
return new static(Str::afterLast($this->value, $search));
8787
}
8888

89+
/**
90+
* Convert the given string to APA-style title case.
91+
*
92+
* @return static
93+
*/
94+
public function apa()
95+
{
96+
return new static(Str::apa($this->value));
97+
}
98+
8999
/**
90100
* Append the given values to the string.
91101
*

tests/StrTest.php

+34
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,40 @@
2525
#[CoversNothing]
2626
class StrTest extends TestCase
2727
{
28+
public function testStringApa()
29+
{
30+
$this->assertSame('Tom and Jerry', Str::apa('tom and jerry'));
31+
$this->assertSame('Tom and Jerry', Str::apa('TOM AND JERRY'));
32+
$this->assertSame('Tom and Jerry', Str::apa('Tom And Jerry'));
33+
34+
$this->assertSame('Back to the Future', Str::apa('back to the future'));
35+
$this->assertSame('Back to the Future', Str::apa('BACK TO THE FUTURE'));
36+
$this->assertSame('Back to the Future', Str::apa('Back To The Future'));
37+
38+
$this->assertSame('This, Then That', Str::apa('this, then that'));
39+
$this->assertSame('This, Then That', Str::apa('THIS, THEN THAT'));
40+
$this->assertSame('This, Then That', Str::apa('This, Then That'));
41+
42+
$this->assertSame('Bond. James Bond.', Str::apa('bond. james bond.'));
43+
$this->assertSame('Bond. James Bond.', Str::apa('BOND. JAMES BOND.'));
44+
$this->assertSame('Bond. James Bond.', Str::apa('Bond. James Bond.'));
45+
46+
$this->assertSame('Self-Report', Str::apa('self-report'));
47+
$this->assertSame('Self-Report', Str::apa('Self-report'));
48+
$this->assertSame('Self-Report', Str::apa('SELF-REPORT'));
49+
50+
$this->assertSame('As the World Turns, So Are the Days of Our Lives', Str::apa('as the world turns, so are the days of our lives'));
51+
$this->assertSame('As the World Turns, So Are the Days of Our Lives', Str::apa('AS THE WORLD TURNS, SO ARE THE DAYS OF OUR LIVES'));
52+
$this->assertSame('As the World Turns, So Are the Days of Our Lives', Str::apa('As The World Turns, So Are The Days Of Our Lives'));
53+
54+
$this->assertSame('To Kill a Mockingbird', Str::apa('to kill a mockingbird'));
55+
$this->assertSame('To Kill a Mockingbird', Str::apa('TO KILL A MOCKINGBIRD'));
56+
$this->assertSame('To Kill a Mockingbird', Str::apa('To Kill A Mockingbird'));
57+
58+
$this->assertSame('', Str::apa(''));
59+
$this->assertSame(' ', Str::apa(' '));
60+
}
61+
2862
public function testCharAt()
2963
{
3064
$this->assertEquals('р', Str::charAt('Привет, мир!', 1));

0 commit comments

Comments
 (0)