Skip to content

Commit 283af0b

Browse files
authored
feat(support): support array parameters in string manipulations (#1073)
1 parent 71efbae commit 283af0b

File tree

3 files changed

+104
-51
lines changed

3 files changed

+104
-51
lines changed

src/Tempest/Support/src/Str/ManipulatesString.php

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,7 @@ public function isAscii(): bool
224224
/**
225225
* Replaces consecutive instances of a given character with a single character.
226226
*/
227-
public function deduplicate(Stringable|string|ArrayAccess|array $characters = ' '): static
227+
public function deduplicate(Stringable|string|iterable $characters = ' '): static
228228
{
229229
return $this->createOrModify(deduplicate($this->value, $characters));
230230
}
@@ -280,47 +280,47 @@ public function classBasename(): static
280280
/**
281281
* Replaces the first occurrence of `$search` with `$replace`.
282282
*/
283-
public function replaceFirst(Stringable|string $search, Stringable|string $replace): static
283+
public function replaceFirst(array|Stringable|string $search, Stringable|string $replace): static
284284
{
285285
return $this->createOrModify(replace_first($this->value, $search, $replace));
286286
}
287287

288288
/**
289289
* Replaces the last occurrence of `$search` with `$replace`.
290290
*/
291-
public function replaceLast(Stringable|string $search, Stringable|string $replace): static
291+
public function replaceLast(array|Stringable|string $search, Stringable|string $replace): static
292292
{
293293
return $this->createOrModify(replace_last($this->value, $search, $replace));
294294
}
295295

296296
/**
297297
* Replaces `$search` with `$replace` if `$search` is at the end of the instance.
298298
*/
299-
public function replaceEnd(Stringable|string $search, Stringable|string $replace): static
299+
public function replaceEnd(array|Stringable|string $search, Stringable|string $replace): static
300300
{
301301
return $this->createOrModify(replace_end($this->value, $search, $replace));
302302
}
303303

304304
/**
305305
* Replaces `$search` with `$replace` if `$search` is at the start of the instance.
306306
*/
307-
public function replaceStart(Stringable|string $search, Stringable|string $replace): static
307+
public function replaceStart(array|Stringable|string $search, Stringable|string $replace): static
308308
{
309309
return $this->createOrModify(replace_start($this->value, $search, $replace));
310310
}
311311

312312
/**
313313
* Strips the specified `$prefix` from the start of the string.
314314
*/
315-
public function stripStart(Stringable|string $prefix): static
315+
public function stripStart(array|Stringable|string $prefix): static
316316
{
317317
return $this->createOrModify(strip_start($this->value, $prefix));
318318
}
319319

320320
/**
321321
* Strips the specified `$suffix` from the end of the string.
322322
*/
323-
public function stripEnd(Stringable|string $suffix): static
323+
public function stripEnd(array|Stringable|string $suffix): static
324324
{
325325
return $this->createOrModify(strip_end($this->value, $suffix));
326326
}
@@ -615,9 +615,9 @@ public function matches(string $regex): bool
615615
* str('Lorem ipsum')->contains('something else'); // false
616616
* ```
617617
*/
618-
public function contains(string|Stringable $needle): bool
618+
public function contains(Stringable|string|array $needle): bool
619619
{
620-
return contains($this->value, (string) $needle);
620+
return contains($this->value, $needle);
621621
}
622622

623623
/**

src/Tempest/Support/src/Str/functions.php

Lines changed: 63 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,9 @@
33
declare(strict_types=1);
44

55
namespace Tempest\Support\Str {
6-
use ArrayAccess;
76
use Countable;
87
use Stringable;
9-
use Tempest\Support\Arr\ImmutableArray;
8+
use Tempest\Support\Arr;
109
use Tempest\Support\Language;
1110
use voku\helper\ASCII;
1211

@@ -177,11 +176,11 @@ function lower_first(Stringable|string $string): string
177176
/**
178177
* Replaces consecutive instances of a given character with a single character.
179178
*/
180-
function deduplicate(Stringable|string $string, Stringable|string|ArrayAccess|array $characters = ' '): string
179+
function deduplicate(Stringable|string $string, Stringable|string|iterable $characters = ' '): string
181180
{
182181
$string = (string) $string;
183182

184-
foreach (arr($characters) as $character) {
183+
foreach (Arr\wrap($characters) as $character) {
185184
$string = preg_replace('/' . preg_quote($character, '/') . '+/u', $character, $string);
186185
}
187186

@@ -231,7 +230,7 @@ function after_first(Stringable|string $string, Stringable|string|array $search)
231230
$nearestPosition = mb_strlen($string); // Initialize with a large value
232231
$foundSearch = '';
233232

234-
foreach (arr($search) as $term) {
233+
foreach (Arr\wrap($search) as $term) {
235234
$position = mb_strpos($string, $term);
236235

237236
if ($position !== false && $position < $nearestPosition) {
@@ -262,7 +261,7 @@ function after_last(Stringable|string $string, Stringable|string|array $search):
262261
$farthestPosition = -1;
263262
$foundSearch = null;
264263

265-
foreach (arr($search) as $term) {
264+
foreach (Arr\wrap($search) as $term) {
266265
$position = mb_strrpos($string, $term);
267266

268267
if ($position !== false && $position > $farthestPosition) {
@@ -292,7 +291,7 @@ function before_first(Stringable|string $string, Stringable|string|array $search
292291

293292
$nearestPosition = mb_strlen($string);
294293

295-
foreach (arr($search) as $char) {
294+
foreach (Arr\wrap($search) as $char) {
296295
$position = mb_strpos($string, $char);
297296

298297
if ($position !== false && $position < $nearestPosition) {
@@ -321,7 +320,7 @@ function before_last(Stringable|string $string, Stringable|string|array $search)
321320

322321
$farthestPosition = -1;
323322

324-
foreach (arr($search) as $char) {
323+
foreach (Arr\wrap($search) as $char) {
325324
$position = mb_strrpos($string, $char);
326325

327326
if ($position !== false && $position > $farthestPosition) {
@@ -383,94 +382,110 @@ function ends_with(Stringable|string $string, Stringable|string|array $needles):
383382
/**
384383
* Replaces the first occurrence of `$search` with `$replace`.
385384
*/
386-
function replace_first(Stringable|string $string, Stringable|string $search, Stringable|string $replace): string
385+
function replace_first(Stringable|string $string, array|Stringable|string $search, Stringable|string $replace): string
387386
{
388387
$string = (string) $string;
389388
$search = normalize_string($search);
390389

391-
if ($search === '') {
392-
return $string;
393-
}
390+
foreach (Arr\wrap($search) as $item) {
391+
if ($search === '') {
392+
continue;
393+
}
394394

395-
$position = strpos($string, (string) $search);
395+
$position = strpos($string, (string) $item);
396396

397-
if ($position === false) {
398-
return $string;
397+
if ($position === false) {
398+
continue;
399+
}
400+
401+
return substr_replace($string, $replace, $position, strlen($item));
399402
}
400403

401-
return substr_replace($string, $replace, $position, strlen($search));
404+
return $string;
402405
}
403406

404407
/**
405408
* Replaces the last occurrence of `$search` with `$replace`.
406409
*/
407-
function replace_last(Stringable|string $string, Stringable|string $search, Stringable|string $replace): string
410+
function replace_last(Stringable|string $string, array|Stringable|string $search, Stringable|string $replace): string
408411
{
409412
$string = (string) $string;
410413
$search = normalize_string($search);
411414

412-
if ($search === '') {
413-
return $string;
414-
}
415+
foreach (Arr\wrap($search) as $item) {
416+
if ($item === '') {
417+
continue;
418+
}
415419

416-
$position = strrpos($string, (string) $search);
420+
$position = strrpos($string, (string) $item);
417421

418-
if ($position === false) {
419-
return $string;
422+
if ($position === false) {
423+
continue;
424+
}
425+
426+
return substr_replace($string, $replace, $position, strlen($item));
420427
}
421428

422-
return substr_replace($string, $replace, $position, strlen($search));
429+
return $string;
423430
}
424431

425432
/**
426433
* Replaces `$search` with `$replace` if `$search` is at the end of the string.
427434
*/
428-
function replace_end(Stringable|string $string, Stringable|string $search, Stringable|string $replace): string
435+
function replace_end(Stringable|string $string, array|Stringable|string $search, Stringable|string $replace): string
429436
{
430437
$string = (string) $string;
431438
$search = normalize_string($search);
432439

433-
if ($search === '') {
434-
return $string;
435-
}
440+
foreach (Arr\wrap($search) as $item) {
441+
if ($search === '') {
442+
continue;
443+
}
436444

437-
if (! ends_with($string, $search)) {
438-
return $string;
445+
if (! ends_with($string, $item)) {
446+
continue;
447+
}
448+
449+
return replace_last($string, $item, $replace);
439450
}
440451

441-
return replace_last($string, $search, $replace);
452+
return $string;
442453
}
443454

444455
/**
445456
* Replaces `$search` with `$replace` if `$search` is at the start of the string.
446457
*/
447-
function replace_start(Stringable|string $string, Stringable|string $search, Stringable|string $replace): string
458+
function replace_start(Stringable|string $string, array|Stringable|string $search, Stringable|string $replace): string
448459
{
449460
$string = (string) $string;
450461

451-
if ($search === '') {
452-
return $string;
453-
}
462+
foreach (Arr\wrap($search) as $item) {
463+
if ($search === '') {
464+
continue;
465+
}
454466

455-
if (! starts_with($string, $search)) {
456-
return $string;
467+
if (! starts_with($string, $item)) {
468+
continue;
469+
}
470+
471+
return replace_first($string, $item, $replace);
457472
}
458473

459-
return replace_first($string, $search, $replace);
474+
return $string;
460475
}
461476

462477
/**
463478
* Strips the specified `$prefix` from the start of the string.
464479
*/
465-
function strip_start(Stringable|string $string, Stringable|string $prefix): string
480+
function strip_start(Stringable|string $string, array|Stringable|string $prefix): string
466481
{
467482
return replace_start($string, $prefix, '');
468483
}
469484

470485
/**
471486
* Strips the specified `$suffix` from the end of the string.
472487
*/
473-
function strip_end(Stringable|string $string, Stringable|string $suffix): string
488+
function strip_end(Stringable|string $string, array|Stringable|string $suffix): string
474489
{
475490
return replace_end($string, $suffix, '');
476491
}
@@ -635,9 +650,15 @@ function substring(Stringable|string $string, int $start, ?int $length = null):
635650
/**
636651
* Checks whether the given string contains the specified `$needle`.
637652
*/
638-
function contains(Stringable|string $string, string|Stringable $needle): bool
653+
function contains(Stringable|string $string, Stringable|string|array $needle): bool
639654
{
640-
return str_contains((string) $string, (string) $needle);
655+
foreach (Arr\wrap($needle) as $item) {
656+
if (str_contains((string) $string, (string) $item)) {
657+
return true;
658+
}
659+
}
660+
661+
return false;
641662
}
642663

643664
/**

src/Tempest/Support/tests/Str/ManipulatesStringTest.php

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,10 @@ public function test_replace_last(): void
247247
$this->assertTrue(str('foobar foobar')->replaceLast('', 'yyy')->equals('foobar foobar'));
248248
$this->assertTrue(str('Malmö Jönköping')->replaceLast('ö', 'xxx')->equals('Malmö Jönkxxxping'));
249249
$this->assertTrue(str('Malmö Jönköping')->replaceLast('', 'yyy')->equals('Malmö Jönköping'));
250+
251+
$this->assertEquals('foobar foobar', str('foobar foobar')->replaceLast([], 'baz')->toString());
252+
$this->assertEquals('foobar bazbar', str('foobar foobar')->replaceLast(['foo', 'bar'], 'baz')->toString());
253+
$this->assertEquals('foobar foobaz', str('foobar foobar')->replaceLast(['bar', 'foo'], 'baz')->toString());
250254
}
251255

252256
public function test_replace_first(): void
@@ -258,6 +262,9 @@ public function test_replace_first(): void
258262
$this->assertTrue(str('foobar foobar')->replaceFirst('', 'yyy')->equals('foobar foobar'));
259263
$this->assertTrue(str('Jönköping Malmö')->replaceFirst('ö', 'xxx')->equals('Jxxxnköping Malmö'));
260264
$this->assertTrue(str('Jönköping Malmö')->replaceFirst('', 'yyy')->equals('Jönköping Malmö'));
265+
266+
$this->assertTrue(str('foobar foobar')->replaceFirst([], 'baz')->equals('foobar foobar'));
267+
$this->assertTrue(str('foobar foobar')->replaceFirst(['foobar', 'foo'], 'baz')->equals('baz foobar'));
261268
}
262269

263270
public function test_replace_end(): void
@@ -270,6 +277,9 @@ public function test_replace_end(): void
270277
$this->assertTrue(str('fooxxx foobar')->replaceEnd('xxx', 'yyy')->equals('fooxxx foobar'));
271278
$this->assertTrue(str('Malmö Jönköping')->replaceEnd('ö', 'xxx')->equals('Malmö Jönköping'));
272279
$this->assertTrue(str('Malmö Jönköping')->replaceEnd('öping', 'yyy')->equals('Malmö Jönkyyy'));
280+
281+
$this->assertEquals('foobar foo', str('foobar foo')->replaceEnd([], 'baz')->toString());
282+
$this->assertEquals('foobar baz', str('foobar foo')->replaceEnd(['bar', 'foo'], 'baz')->toString());
273283
}
274284

275285
public function test_append(): void
@@ -602,6 +612,8 @@ public function test_contains(): void
602612
{
603613
$this->assertTrue(str('foo')->contains('fo'));
604614
$this->assertFalse(str('foo')->contains('bar'));
615+
$this->assertTrue(str('foo')->contains(['bar', 'foo']));
616+
$this->assertFalse(str('foo')->contains([]));
605617
}
606618

607619
public function test_levenshtein(): void
@@ -723,4 +735,24 @@ public function test_sentence(string $input, string $output): void
723735
{
724736
$this->assertEquals($output, str($input)->sentence()->toString());
725737
}
738+
739+
#[TestWith(['http://tempestphp.com', 'http://', 'tempestphp.com'])]
740+
#[TestWith(['http://tempestphp.com', ['http://', 'https://'], 'tempestphp.com'])]
741+
#[TestWith(['http://tempestphp.com', '', 'http://tempestphp.com'])]
742+
#[TestWith(['http://tempestphp.com', [], 'http://tempestphp.com'])]
743+
#[TestWith(['http://tempestphp.com', '://', 'http://tempestphp.com'])]
744+
#[TestWith(['http://tempestphp.com', ['http', 'http://'], '://tempestphp.com'])]
745+
public function test_strip_start(string $input, string|array $strip, string $output): void
746+
{
747+
$this->assertEquals($output, str($input)->stripStart($strip)->toString());
748+
}
749+
750+
#[TestWith(['foo_bar', '_bar', 'foo'])]
751+
#[TestWith(['foo.bar/', '/', 'foo.bar'])]
752+
#[TestWith(['foo.bar/', ['/', 'bar/'], 'foo.bar'])]
753+
#[TestWith(['foo.bar/', ['bar/', '/'], 'foo.'])]
754+
public function test_strip_end(string $input, string|array $strip, string $output): void
755+
{
756+
$this->assertEquals($output, str($input)->stripEnd($strip)->toString());
757+
}
726758
}

0 commit comments

Comments
 (0)