laravel / framework

The Laravel Framework.
https://laravel.com
MIT License
32.69k stars 11.05k forks source link

[11.x] Add `splitLast` string helper method #53505

Closed ash-jc-allen closed 3 days ago

ash-jc-allen commented 2 weeks ago

Hey! This PR proposes a new Str::splitLast helper method for use with strings. It splits a string into 2 pieces based on the last occurrence of a search value.

Apologies if something like this already exists and I've just not seen it haha!

I'm not sure if it's something that'd be useful to anyone else outside my current project, but I thought I'd propose it just in case.

Context

I've recently been working on a feature for a project where I need to split a full software name (e.g. Google Chrome 10) to get it's name and version number (e.g. "Google Chrome" and "10").

I was using something like this:

$fullSoftwareName = 'laravel framework 12';

$softwareName = Str::beforeLast($fullSoftwareName, ' '); // laravel framework
$softwareVersion = Str::afterLast($fullSoftwareName, ' '); // 12

I thought it'd be nice to use something like this that wraps it all up:

$fullSoftwareName = 'laravel framework 12';

[$softwareName, $softwareVersion] = Str::splitLast($fullSoftwareName, ' ');

// $softwareName: 'laravel framework'
// $softwareVersion: '12'

Examples

By default, the search value won't be included in the returned result:

[$before, $after] = Str::splitLast('taylor otwell', 'twe');

// $before: 'taylor o'
// $after: 'll'

Or, you can pass "before" to the includeSearch argument to append the search value to the first item:

[$before, $after] = Str::splitLast('taylor otwell', 'twe', includeSearch: 'before');

// $before: 'taylor otwe'
// $after: 'll'

Or, you can pass "after" to the includeSearch argument to prepend the search value to the second item:

[$before, $after] = Str::splitLast('taylor otwell', 'twe', includeSearch: 'after');

// $before: 'taylor o'
// $after: 'twell'

If the search value isn't found (or an empty string is passed as the search value), then the subject will be returned as the first value of the array:

[$before, $after] = Str::splitLast('taylor otwell', 'ash');

// $before: 'taylor otwell'
// $after: ''

As I say, I don't know if this is just a niche use case that won't be encountered that often, but I thought I'd propose it in case in could come in handy for anyone else.

If it's something you think might be worth merging, please let me know if there's anything you'd like me to change 😄

taylorotwell commented 2 weeks ago

Agree I don't love passing 'before' or 'after' as strings in that last argument.

ash-jc-allen commented 2 weeks ago

@morloderex @taylorotwell I completely agree about that last argument. It felt a little bit icky when I was writing it, but I couldn't think what would be the better approach, haha!

@taylorotwell Do you like the idea that @morloderex has proposed about updating the signature to this?:

splitLast($subject, $search, $appendSearch = false, $prependSearch = false)

If so, I'm happy to get that added 😄

I quite like the look of:

[$before, $after] = Str::splitLast('taylor otwell', 'twe', prependSearch: true);
[$before, $after] = Str::splitLast('taylor otwell', 'twe', appendSearch: true);
ash-jc-allen commented 1 week ago

Hey! I've gone out on a bit of a whim and made the changes that @morloderex suggested. Hopefully, this looks a bit nicer to use? 🤞😄

taylorotwell commented 3 days ago

I think I'll leave this one to just be a package / macro for now if that's cool. 👍