Skip to content

Commit a2ec874

Browse files
committed
[String] Add WORD_STRICT mode to truncate method
1 parent 9f77ba3 commit a2ec874

File tree

4 files changed

+75
-10
lines changed

4 files changed

+75
-10
lines changed

src/Symfony/Component/String/AbstractString.php

+15-2
Original file line numberDiff line numberDiff line change
@@ -605,8 +605,12 @@ public function trimSuffix($suffix): static
605605
return $str;
606606
}
607607

608-
public function truncate(int $length, string $ellipsis = '', bool $cut = true): static
608+
public function truncate(int $length, string $ellipsis = '', bool|TruncateCut $cut = TruncateCut::Char): static
609609
{
610+
if (\is_bool($cut)) {
611+
$cut = $cut ? TruncateCut::Char : TruncateCut::WordAfterWord;
612+
}
613+
610614
$stringLength = $this->length();
611615

612616
if ($stringLength <= $length) {
@@ -619,7 +623,8 @@ public function truncate(int $length, string $ellipsis = '', bool $cut = true):
619623
$ellipsisLength = 0;
620624
}
621625

622-
if (!$cut) {
626+
$desiredLength = $length;
627+
if (TruncateCut::WordAfterWord === $cut || TruncateCut::Word === $cut) {
623628
if (null === $length = $this->indexOf([' ', "\r", "\n", "\t"], ($length ?: 1) - 1)) {
624629
return clone $this;
625630
}
@@ -629,6 +634,14 @@ public function truncate(int $length, string $ellipsis = '', bool $cut = true):
629634

630635
$str = $this->slice(0, $length - $ellipsisLength);
631636

637+
if (TruncateCut::Word === $cut) {
638+
if (0 === $ellipsisLength && $desiredLength === $this->indexOf([' ', "\r", "\n", "\t"], $length)) {
639+
return $str;
640+
}
641+
642+
$str = $str->beforeLast([' ', "\r", "\n", "\t"]);
643+
}
644+
632645
return $ellipsisLength ? $str->trimEnd()->append($ellipsis) : $str;
633646
}
634647

src/Symfony/Component/String/CHANGELOG.md

+5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
CHANGELOG
22
=========
33

4+
7.2
5+
---
6+
7+
* Add `TruncateCut::Word` mode to truncate method
8+
49
7.1
510
---
611

src/Symfony/Component/String/Tests/AbstractAsciiTestCase.php

+13-8
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
use Symfony\Component\String\ByteString;
1717
use Symfony\Component\String\CodePointString;
1818
use Symfony\Component\String\Exception\InvalidArgumentException;
19+
use Symfony\Component\String\TruncateCut;
1920
use Symfony\Component\String\UnicodeString;
2021

2122
abstract class AbstractAsciiTestCase extends TestCase
@@ -1498,30 +1499,34 @@ public static function providePadStart()
14981499
/**
14991500
* @dataProvider provideTruncate
15001501
*/
1501-
public function testTruncate(string $expected, string $origin, int $length, string $ellipsis, bool $cut = true)
1502+
public function testTruncate(string $expected, string $origin, int $length, string $ellipsis, TruncateCut $cut = TruncateCut::Char)
15021503
{
15031504
$instance = static::createFromString($origin)->truncate($length, $ellipsis, $cut);
15041505

15051506
$this->assertEquals(static::createFromString($expected), $instance);
15061507
}
15071508

1508-
public static function provideTruncate()
1509+
public static function provideTruncate(): array
15091510
{
15101511
return [
15111512
['', '', 3, ''],
15121513
['', 'foo', 0, '...'],
1513-
['foo', 'foo', 0, '...', false],
1514+
['foo', 'foo', 0, '...', TruncateCut::WordAfterWord],
15141515
['fo', 'foobar', 2, ''],
15151516
['foobar', 'foobar', 10, ''],
1516-
['foobar', 'foobar', 10, '...', false],
1517+
['foobar', 'foobar', 10, '...', TruncateCut::WordAfterWord],
15171518
['foo', 'foo', 3, '...'],
15181519
['fo', 'foobar', 2, '...'],
15191520
['...', 'foobar', 3, '...'],
15201521
['fo...', 'foobar', 5, '...'],
1521-
['foobar...', 'foobar foo', 6, '...', false],
1522-
['foobar...', 'foobar foo', 7, '...', false],
1523-
['foobar foo...', 'foobar foo a', 10, '...', false],
1524-
['foobar foo aar', 'foobar foo aar', 12, '...', false],
1522+
['foobar...', 'foobar foo', 6, '...', TruncateCut::WordAfterWord],
1523+
['foobar...', 'foobar foo', 7, '...', TruncateCut::WordAfterWord],
1524+
['foobar foo...', 'foobar foo a', 10, '...', TruncateCut::WordAfterWord],
1525+
['foobar foo aar', 'foobar foo aar', 12, '...', TruncateCut::WordAfterWord],
1526+
['foobar foo', 'foobar foo aar', 10, '', TruncateCut::Word],
1527+
['foobar...', 'foobar foo aar', 10, '...', TruncateCut::Word],
1528+
['Lorem ipsum', 'Lorem ipsum dolor sit amet', 14, '', TruncateCut::Word],
1529+
['Lorem...', 'Lorem ipsum dolor sit amet', 10, '...', TruncateCut::Word],
15251530
];
15261531
}
15271532

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\String;
13+
14+
enum TruncateCut
15+
{
16+
/**
17+
* Will cut exactly at given length.
18+
*
19+
* Length: 14
20+
* Source: Lorem ipsum dolor sit amet
21+
* Output: Lorem ipsum do
22+
*/
23+
case Char;
24+
25+
/**
26+
* Will cut at given length, if length is onto a word, will cut before it.
27+
*
28+
* Length: 14
29+
* Source: Lorem ipsum dolor sit amet
30+
* Output: Lorem ipsum
31+
*/
32+
case Word;
33+
34+
/**
35+
* Will cut at given length until the end of the current word if length is onto a word.
36+
*
37+
* Length: 14
38+
* Source: Lorem ipsum dolor sit amet
39+
* Output: Lorem ipsum dolor
40+
*/
41+
case WordAfterWord;
42+
}

0 commit comments

Comments
 (0)