Passed
Push — master ( 42571c...f8295f )
by stéphane
09:20
created

Regex::isDate()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 14
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 4

Importance

Changes 0
Metric Value
cc 4
eloc 11
c 0
b 0
f 0
nc 4
nop 1
dl 0
loc 14
ccs 12
cts 12
cp 1
crap 4
rs 9.9
1
<?php
2
3
namespace Dallgoot\Yaml;
4
5
/**
6
 * Define Regex patterns as constants
7
 * and some 'testing-type' methods
8
 *
9
 * @author  Stéphane Rebai <[email protected]>
10
 * @license Apache 2.0
11
 * @link    https://github.com/dallgoot/yaml
12
 */
13
class Regex
14
{
15
    const OCTAL_NUM = "/^0o\d+$/i";
16
    const HEX_NUM   = "/^0x[\da-f]+$/i";
17
    const BIN_NUM   = "/^0b[01]+$/i";
18
19
    const QUOTED = "(?'quot'(?'q'['\"]).*?(?<![\\\\])(?&q))";
20
    const NUM    = "(?'num'[\\-+]?(?:\\d+\\.?(?:\\d*(e[+\\-]?\\d+)?)|(\\.(inf|nan))))";
21
    const WORD   = "(?'word'[[:alnum:] _\\-\\.]+)";
22
    const RC     = "(?'rc'\\*\\w+)"; //reference call
23
    // const RC     = "(?'rc'\\*[^ *&]+)"; //reference call
24
    const RD     = "(?'rd'&\\w+)"; //reference definition
25
    // const RD     = "(?'rd'&[^ &*]+)"; //reference definition
26
    // const TAG    = "(?'tag'!!?[\\w\\/\\-]+!?)";
27
    const TAG    = "(?'tag'!!?[^! ]+!?)";
28
    const ALL    = "(?'all'(?:(?:(?&rd)|(?&tag)) +)?(?:(?&quot)|(?&rc)|(?&word)|(?&map)|(?&seq)))";
29
    const MAP    = "(?'map'\\{ *?(?'pair'((?:(?&quot)|[^:]+) *?: *(?&all)) *,? *)* *?\\})";
30
    // const MAP    = "(?'map'\\{ *((?:(?&quot)|(?&word)) *: *(?&all) *(?:, *(?:(?&quot)|(?&word)) *: *(?&all)))*\\})";
31
    // const SEQ    = "(?'seq'\\[ *(?:(?'i'(?&all)) *,? *)* *\\])";
32
    const SEQ    = "(?'seq'\\[ *((?&all) *(?:, *(?&all))*)* *\\])";
33
    const ALLDEF = "(?(DEFINE)".Regex::QUOTED.
34
                                Regex::RC.
35
                                Regex::WORD.
36
                                Regex::TAG.
37
                                Regex::RD.
38
                                Regex::ALL.
39
                                Regex::MAP.
40
                                Regex::SEQ.")";
41
42
    const MAPPING  = "/".Regex::ALLDEF."^(?&map)$/i";
43
    const MAPPING_VALUES = "/".Regex::ALLDEF."(?'k'(?&quot)|[^:]+) *: *(?'v'(?&all)) *,? */i";
44
45
    const SEQUENCE = "/".Regex::ALLDEF."^(?&seq)$/i";
46
    const SEQUENCE_VALUES = "/".Regex::ALLDEF."(?'item'(?&all)) *,? */i";
47
48
    const KEY  = "/^([\\w'\"~!][\\w'\" \\-.\\/~!]*[ \\t]*)(?::([ \\t]+[^\\n]+)|:[ \\t]*)$/i";
49
    # const KEY  = '/^([^:#]+)[ \t]*:([ \t]+.+)*$/iu';
50
    const ITEM = '/^-([ \t]+(.*))?$/';
51
52
    const NODE_ACTIONS = "/(?(DEFINE)".Regex::RC.Regex::RD.Regex::TAG.")(?'action'(?&rc)|(?&rd)|(?&tag))( +(?'content'.*))?$/";
53
54
    // %TAG ! tag:example.com,2000:app/
55
    // %TAG !! tag:example.com,2000:app/
56
    // %TAG !e! tag:example.com,2000:app/
57
    // %TAG !m! !my-
58
    // !<!bar> baz
59
    // !<tag:clarkevans.com,2002:invoice>
60
    const TAG_URI = "(?'url'tag:\\w+\\.\\w{2,},\\d{4}:\\w*)";
61
    const TAG_PARTS = "/(?'handle'!(?:[\\w\\d\\-_]!|!)*)(?'tagname'(?:<!?)?[\\w\\d\\-:.,_]+>?)?/i";
62
    const DIRECTIVE_TAG = "/(?(DEFINE)".Regex::TAG_URI.")%TAG +(?'handle'![\\w\\d\-_]+!|!!|!) +(?'uri'(?&url)|(?'prefix'![\\w\\d\-_]+))/i";
63
    const DIRECTIVE_VERSION = "/%YAML *:? *(?'version'1\\.\\d)/i";
64
65
66
    /**
67
     * Determines if a valid Date format
68
     * @param string $v a string value
69
     * @return bool
70
     * @throws \Exception if any preg_match has invalid regex
71
     * @todo : support other date formats ???
72
     */
73 1
    public static function isDate(string $v):bool
74
    {
75 1
        $d         = "\\d{4}([-\\/])\\d{2}\\1\\d{2}";
76 1
        $h         = "\\d{2}(:)\\d{2}\\2\\d{2}";
77 1
        $date      = "/^$d$/"; // 2002-12-14, 2002/12/14
78 1
        $canonical = "/^$d(?:t| )$h\\.\\dz?$/im"; // 2001-12-15T02:59:43.1Z
79 1
        $spaced    = "/^$d(?:t| )$h\\.\\d{2} [-+]\\d$/im"; // 2001-12-14 21:59:43.10 -5
80 1
        $iso8601   = "/^$d(?:t| )$h\\.\\d{2}[-+]\\d{2}\\2\\d{2}/im"; // 2001-12-14t21:59:43.10-05:00
81 1
        $matchDate      = preg_match($date, $v);
82 1
        $matchCanonical = preg_match($canonical, $v);
83 1
        $matchSpaced    = preg_match($spaced, $v);
84 1
        $matchIso       = preg_match($iso8601, $v);
85
86 1
        return $matchDate || $matchCanonical || $matchSpaced || $matchIso;
87
    }
88
89
    /**
90
     * Determines if number.
91
     *
92
     * @param string $var A string value
93
     *
94
     * @return boolean  True if number, False otherwise.
95
     */
96 1
    public static function isNumber(string $var):bool
97
    {
98
        // && (bool) preg_match("/^((0o\d+)|(0x[\da-f]+)|([\d.]+e[-+]\d{1,2})|([-+]?(\d*\.?\d+)))$/i", $var);
99 1
        return is_numeric($var)
100 1
                || (bool) preg_match(Regex::OCTAL_NUM, $var)
101 1
                || (bool) preg_match(Regex::HEX_NUM, $var)
102 1
                || (bool) preg_match(Regex::BIN_NUM, $var);
103
    }
104
105
    /**
106
     * Determines if properly quoted.
107
     *
108
     * @param string $var The variable
109
     *
110
     * @return boolean True if properly quoted, False otherwise.
111
     */
112 1
    public static function isProperlyQuoted(string $var):bool
113
    {
114 1
        return (bool) preg_match("/^(['\"]).*?(?<![\\\\])\\1$/s", trim($var));
115
    }
116
}
117