Passed
Branch master (09b7c0)
by stéphane
02:52
created

Regex::isProperlyQuoted()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

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