Completed
Pull Request — master (#38)
by Radosław
04:20
created

RegExp   A

Complexity

Total Complexity 17

Size/Duplication

Total Lines 117
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 38
dl 0
loc 117
c 0
b 0
f 0
rs 10
wmc 17

10 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 1
A of() 0 5 2
A hasDelimiters() 0 14 4
A wrapInDelimiters() 0 5 2
A fromString() 0 13 2
A test() 0 3 1
A isValidDelimiter() 0 3 1
A isGlobal() 0 3 1
A matchAll() 0 12 2
A __toString() 0 3 1
1
<?php
2
declare(strict_types=1);
3
4
namespace Baethon\Phln;
5
6
use Baethon\Phln\Phln as P;
7
8
final class RegExp
9
{
10
    /**
11
     * @var string
12
     */
13
    private $pattern;
14
15
    /**
16
     * @var string
17
     */
18
    private $modifiers;
19
20
    /**
21
     * @var bool
22
     */
23
    private $global = false;
24
25
    public function __construct(string $pattern, string $modifiers = '')
26
    {
27
        $this->pattern = $this->wrapInDelimiters($pattern);
28
        $this->modifiers = str_replace('g', '', $modifiers);
29
        $this->global = (false !== strstr($modifiers, 'g'));
30
    }
31
32
    public function isGlobal(): bool
33
    {
34
        return $this->global;
35
    }
36
37
    public function __toString(): string
38
    {
39
        return $this->pattern.$this->modifiers;
40
    }
41
42
    private function wrapInDelimiters(string $pattern): string
43
    {
44
        return $this->hasDelimiters($pattern) ? $pattern : sprintf(
45
            '/%s/',
46
            preg_quote($pattern, '/')
47
        );
48
    }
49
50
    /**
51
     * Checks if pattern has valid delimiter
52
     *
53
     * @param string $pattern
54
     * @return bool
55
     * @see https://secure.php.net/manual/en/regexp.reference.delimiters.php
56
     */
57
    private function hasDelimiters(string $pattern): bool
58
    {
59
        if (mb_strlen($pattern) < 2) {
60
            return false;
61
        }
62
63
        $start = substr($pattern, 0, 1);
64
        $end = substr($pattern, -1);
65
66
        if ($start !== $end) {
67
            return false;
68
        }
69
70
        return static::isValidDelimiter($start) && static::isValidDelimiter($end);
71
    }
72
73
    private static function isValidDelimiter(string $char): bool
74
    {
75
        return (bool) preg_match('/^[^a-z0-9\s]$/', $char);
76
    }
77
78
    /**
79
     * Creates RegExp instance based on passed regular expression.
80
     *
81
     * @param string $regexp
82
     * @return RegExp
83
     * @example
84
     *      RegExp::fromString('/foo/gi'); // -> new RegExp('/foo/', 'gi');
85
     */
86
    public static function fromString(string $regexp): RegExp
87
    {
88
        $start = substr($regexp, 0, 1);
89
90
        if (false === static::isValidDelimiter($start)) {
91
            return new static($regexp);
92
        }
93
94
        $endPosition = strrpos($regexp, $start);
95
        $pattern = substr($regexp, 0, $endPosition + 1);
96
        $modifiers = substr($regexp, $endPosition + 1);
97
98
        return new static($pattern, $modifiers);
99
    }
100
101
    public static function of($regexp): RegExp
102
    {
103
        return ($regexp instanceof static)
104
            ? $regexp
105
            : static::fromString($regexp);
106
    }
107
108
    public function matchAll(string $test): array
109
    {
110
        $matches = [];
111
        preg_match_all((string) $this, $test, $matches, PREG_SET_ORDER);
112
113
        $slice = function ($list) {
114
            return count($list) > 1
115
                ? array_slice($list, 1)
116
                : $list;
117
        };
118
119
        return P::flatMap($slice, $matches);
0 ignored issues
show
Bug Best Practice introduced by
The expression return Baethon\Phln\Phln...atMap($slice, $matches) could return the type callable which is incompatible with the type-hinted return array. Consider adding an additional type-check to rule them out.
Loading history...
120
    }
121
122
    public function test(string $string): bool
123
    {
124
        return (bool) preg_match((string) $this, $string);
125
    }
126
}
127