Implemented custom Glob::toRegex() method

This commit is contained in:
Chris Kankiewicz
2020-04-20 14:48:55 -07:00
parent 3b1084b503
commit 0767922306
3 changed files with 142 additions and 6 deletions

View File

@@ -3,11 +3,11 @@
namespace App\Factories;
use App\SortMethods;
use App\Support\Glob;
use Closure;
use DI\Container;
use RuntimeException;
use Symfony\Component\Finder\Finder;
use Symfony\Component\Finder\Glob;
use Symfony\Component\Finder\SplFileInfo;
use Tightenco\Collect\Support\Collection;
@@ -81,12 +81,10 @@ class FinderFactory
$this->container->get('hidden_files')
)->when($this->container->get('hide_app_files'), static function (Collection $collection) {
return $collection->merge(self::APP_FILES);
})->map(static function (string $pattern): string {
return DIRECTORY_SEPARATOR . ltrim($pattern, DIRECTORY_SEPARATOR);
})->unique();
return substr_replace(Glob::toRegex(
sprintf('%s{%s}', $this->container->get('base_path'), $collection->implode(','))
), '', -2, 1);
return Glob::toRegex(
sprintf('%s/{%s}', $this->container->get('base_path'), $collection->implode(','))
);
}
}

101
app/src/Support/Glob.php Normal file
View File

@@ -0,0 +1,101 @@
<?php
namespace App\Support;
class Glob
{
/**
* Convert a glob pattern to a regular expression pattern.
*
* @param string $glob
*
* @return string
*/
public static function toRegex(string $glob): string
{
$pattern = '';
$characterGroup = 0;
$patternGroup = 0;
for ($i = 0; $i < strlen($glob); ++$i) {
$char = $glob[$i];
switch ($char) {
case '\\':
$pattern .= '\\' . $glob[++$i];
break;
case '?':
$pattern .= '.';
break;
case '*':
if (isset($glob[$i + 1]) && $glob[$i + 1] === '*') {
$pattern .= '.*';
++$i;
} else {
$pattern .= '[^/]*';
}
break;
case '#':
$pattern .= '\#';
break;
case '[':
$pattern .= $char;
++$characterGroup;
break;
case ']':
if ($characterGroup > 0) {
--$characterGroup;
}
$pattern .= $char;
break;
case '^':
if ($characterGroup > 0) {
$pattern .= $char;
} else {
$pattern .= '\\' . $char;
}
break;
case '{':
$pattern .= '(';
++$patternGroup;
break;
case '}':
if ($patternGroup > 0) {
$pattern .= ')';
--$patternGroup;
} else {
$pattern .= $char;
}
break;
case ',':
if ($patternGroup > 0) {
$pattern .= '|';
} else {
$pattern .= $char;
}
break;
default:
if (in_array($char, ['.', '(', ')', '|', '+', '$'])) {
$pattern .= '\\' . $char;
} else {
$pattern .= $char;
}
break;
}
}
return sprintf('#^%s#', $pattern);
}
}

View File

@@ -0,0 +1,37 @@
<?php
namespace Tests\Support;
use App\Support\Glob;
use Tests\TestCase;
class GlobTest extends TestCase
{
public function test_it_converts_glob_pattern_special_characters_to_a_regular_expression(): void
{
$this->assertSame('#^#', Glob::toRegex(''));
$this->assertSame('#^\\\\#', Glob::toRegex('\\\\'));
$this->assertSame('#^.#', Glob::toRegex('?'));
$this->assertSame('#^[^/]*#', Glob::toRegex('*'));
$this->assertSame('#^.*#', Glob::toRegex('**'));
$this->assertSame('#^\##', Glob::toRegex('#'));
$this->assertSame('#^\\?#', Glob::toRegex('\\?'));
}
public function test_it_converts_a_glob_pattern_to_a_regular_expression_pattern(): void
{
$this->assertSame('#^foo\.txt#', Glob::toRegex('foo.txt'));
$this->assertSame('#^foo/bar\.txt#', Glob::toRegex('foo/bar.txt'));
$this->assertSame('#^foo\?bar\.txt#', Glob::toRegex('foo\?bar.txt'));
$this->assertSame('#^[^/]*\.txt#', Glob::toRegex('*.txt'));
$this->assertSame('#^.*/[^/]*\.txt#', Glob::toRegex('**/*.txt'));
$this->assertSame('#^([^/]*|.*/[^/]*)\.txt#', Glob::toRegex('{*,**/*}.txt'));
$this->assertSame('#^file\.(yml|yaml)#', Glob::toRegex('file.{yml,yaml}'));
$this->assertSame('#^[fbw]oo\.txt#', Glob::toRegex('[fbw]oo.txt'));
$this->assertSame('#^[^fbw]oo\.txt#', Glob::toRegex('[^fbw]oo.txt'));
$this->assertSame('#^foo}bar\.txt#', Glob::toRegex('foo}bar.txt'));
$this->assertSame('#^foo\^bar\.txt#', Glob::toRegex('foo^bar.txt'));
$this->assertSame('#^foo,bar\.txt#', Glob::toRegex('foo,bar.txt'));
$this->assertSame('#^foo/.*/[^/]*\.txt#', Glob::toRegex('foo/**/*.txt'));
}
}