diff --git a/README.md b/README.md index 0774030..d1e7c14 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,7 @@ s('string')->toTitleCase()->ensureRight('y') == 'Stringy' * [Instance methods](#instance-methods) * [append](#appendstring-string) * [at](#atint-index) + * [between](#betweenstring-start-string-end--int-offset) * [camelize](#camelize) * [chars](#chars) * [collapseWhitespace](#collapsewhitespace) @@ -229,6 +230,16 @@ Returns the character at $index, with indexes starting at 0. S::create('fòô bàř')->at(6); // 'ř' ``` +##### between(string $start, string $end [, int $offset]) + +Returns the substring between $start and $end, if found, or an empty +string. An optional offset may be supplied from which to begin the +search for the start string. + +```php +S::create('{foo} and {bar}')->between('{', '}'); // 'foo' +``` + ##### camelize() Returns a camelCase version of the string. Trims surrounding spaces, diff --git a/src/Stringy.php b/src/Stringy.php index 8dcb623..1d4f3ef 100644 --- a/src/Stringy.php +++ b/src/Stringy.php @@ -878,6 +878,32 @@ class Stringy implements \Countable, \IteratorAggregate, \ArrayAccess ->removeLeft($replacement)->removeRight($replacement); } + /** + * Returns the substring between $start and $end, if found, or an empty + * string. An optional offset may be supplied from which to begin the + * search for the start string. + * + * @param string $start Delimiter marking the start of the substring + * @param string $end Delimiter marketing the end of the substring + * @param string $offset Index from which to begin the search + * @return Stringy Object whose $str has been converted to an URL slug + */ + public function between($start, $end, $offset = 0) + { + $startIndex = $this->indexOf($start, $offset); + if ($startIndex === false) { + return static::create('', $this->encoding); + } + + $substrIndex = $startIndex + mb_strlen($start, $this->encoding); + $endIndex = $this->indexOf($end, $substrIndex); + if ($endIndex === false) { + return static::create('', $this->encoding); + } + + return $this->substr($substrIndex, $endIndex - $substrIndex); + } + /** * Returns true if the string contains $needle, false otherwise. By default * the comparison is case-sensitive, but can be made insensitive by setting diff --git a/tests/StringyTest.php b/tests/StringyTest.php index f40e371..3177d2f 100644 --- a/tests/StringyTest.php +++ b/tests/StringyTest.php @@ -1002,6 +1002,41 @@ class StringyTestCase extends PHPUnit_Framework_TestCase ); } + /** + * @dataProvider betweenProvider() + */ + public function testBetween($expected, $str, $start, $end, $offset = null, + $encoding = null) + { + $stringy = S::create($str, $encoding); + $result = $stringy->between($start, $end, $offset); + $this->assertStringy($result); + $this->assertEquals($expected, $result); + $this->assertEquals($str, $stringy); + } + + public function betweenProvider() + { + return array( + array('', 'foo', '{', '}'), + array('', '{foo', '{', '}'), + array('foo', '{foo}', '{', '}'), + array('{foo', '{{foo}', '{', '}'), + array('', '{}foo}', '{', '}'), + array('foo', '}{foo}', '{', '}'), + array('foo', 'A description of {foo} goes here', '{', '}'), + array('bar', '{foo} and {bar}', '{', '}', 1), + array('', 'fòô', '{', '}', 0, 'UTF-8'), + array('', '{fòô', '{', '}', 0, 'UTF-8'), + array('fòô', '{fòô}', '{', '}', 0, 'UTF-8'), + array('{fòô', '{{fòô}', '{', '}', 0, 'UTF-8'), + array('', '{}fòô}', '{', '}', 0, 'UTF-8'), + array('fòô', '}{fòô}', '{', '}', 0, 'UTF-8'), + array('fòô', 'A description of {fòô} goes here', '{', '}', 0, 'UTF-8'), + array('bàř', '{fòô} and {bàř}', '{', '}', 1, 'UTF-8') + ); + } + /** * @dataProvider containsProvider() */