scratch – Diff between revs 75 and 125
?pathlinks?
Rev 75 | Rev 125 | |||
---|---|---|---|---|
1 | |
1 | |
|
2 | # Pattern is a zero-conflict wrapper extending RegExp features |
2 | # Pattern is a zero-conflict wrapper extending RegExp features |
|
3 | # in order to make YAML parsing regex more expressive. |
3 | # in order to make YAML parsing regex more expressive. |
|
4 | # |
4 | # |
|
5 | class Pattern |
5 | class Pattern |
|
6 | |
6 | |
|
7 | # @property [RegExp] The RegExp instance |
7 | # @property [RegExp] The RegExp instance |
|
8 | regex: null |
8 | regex: null |
|
9 | |
9 | |
|
10 | # @property [String] The raw regex string |
10 | # @property [String] The raw regex string |
|
11 | rawRegex: null |
11 | rawRegex: null |
|
12 | |
12 | |
|
13 | # @property [String] The cleaned regex string (used to create the RegExp instance) |
13 | # @property [String] The cleaned regex string (used to create the RegExp instance) |
|
14 | cleanedRegex: null |
14 | cleanedRegex: null |
|
15 | |
15 | |
|
16 | # @property [Object] The dictionary mapping names to capturing bracket numbers |
16 | # @property [Object] The dictionary mapping names to capturing bracket numbers |
|
17 | mapping: null |
17 | mapping: null |
|
18 | |
18 | |
|
19 | # Constructor |
19 | # Constructor |
|
20 | # |
20 | # |
|
21 | # @param [String] rawRegex The raw regex string defining the pattern |
21 | # @param [String] rawRegex The raw regex string defining the pattern |
|
22 | # |
22 | # |
|
23 | constructor: (rawRegex, modifiers = '') -> |
23 | constructor: (rawRegex, modifiers = '') -> |
|
24 | cleanedRegex = '' |
24 | cleanedRegex = '' |
|
25 | len = rawRegex.length |
25 | len = rawRegex.length |
|
26 | mapping = null |
26 | mapping = null |
|
27 | |
27 | |
|
28 | # Cleanup raw regex and compute mapping |
28 | # Cleanup raw regex and compute mapping |
|
29 | capturingBracketNumber = 0 |
29 | capturingBracketNumber = 0 |
|
30 | i = 0 |
30 | i = 0 |
|
31 | while i < len |
31 | while i < len |
|
32 | _char = rawRegex.charAt(i) |
32 | _char = rawRegex.charAt(i) |
|
33 | if _char is '\\' |
33 | if _char is '\\' |
|
34 | # Ignore next character |
34 | # Ignore next character |
|
35 | cleanedRegex += rawRegex[i..i+1] |
35 | cleanedRegex += rawRegex[i..i+1] |
|
36 | i++ |
36 | i++ |
|
37 | else if _char is '(' |
37 | else if _char is '(' |
|
38 | # Increase bracket number, only if it is capturing |
38 | # Increase bracket number, only if it is capturing |
|
39 | if i < len - 2 |
39 | if i < len - 2 |
|
40 | part = rawRegex[i..i+2] |
40 | part = rawRegex[i..i+2] |
|
41 | if part is '(?:' |
41 | if part is '(?:' |
|
42 | # Non-capturing bracket |
42 | # Non-capturing bracket |
|
43 | i += 2 |
43 | i += 2 |
|
44 | cleanedRegex += part |
44 | cleanedRegex += part |
|
45 | else if part is '(?<' |
45 | else if part is '(?<' |
|
46 | # Capturing bracket with possibly a name |
46 | # Capturing bracket with possibly a name |
|
47 | capturingBracketNumber++ |
47 | capturingBracketNumber++ |
|
48 | i += 2 |
48 | i += 2 |
|
49 | name = '' |
49 | name = '' |
|
50 | while i + 1 < len |
50 | while i + 1 < len |
|
51 | subChar = rawRegex.charAt(i + 1) |
51 | subChar = rawRegex.charAt(i + 1) |
|
52 | if subChar is '>' |
52 | if subChar is '>' |
|
53 | cleanedRegex += '(' |
53 | cleanedRegex += '(' |
|
54 | i++ |
54 | i++ |
|
55 | if name.length > 0 |
55 | if name.length > 0 |
|
56 | # Associate a name with a capturing bracket number |
56 | # Associate a name with a capturing bracket number |
|
57 | mapping ?= {} |
57 | mapping ?= {} |
|
58 | mapping[name] = capturingBracketNumber |
58 | mapping[name] = capturingBracketNumber |
|
59 | break |
59 | break |
|
60 | else |
60 | else |
|
61 | name += subChar |
61 | name += subChar |
|
62 | |
62 | |
|
63 | i++ |
63 | i++ |
|
64 | else |
64 | else |
|
65 | cleanedRegex += _char |
65 | cleanedRegex += _char |
|
66 | capturingBracketNumber++ |
66 | capturingBracketNumber++ |
|
67 | else |
67 | else |
|
68 | cleanedRegex += _char |
68 | cleanedRegex += _char |
|
69 | else |
69 | else |
|
70 | cleanedRegex += _char |
70 | cleanedRegex += _char |
|
71 | |
71 | |
|
72 | i++ |
72 | i++ |
|
73 | |
73 | |
|
74 | @rawRegex = rawRegex |
74 | @rawRegex = rawRegex |
|
75 | @cleanedRegex = cleanedRegex |
75 | @cleanedRegex = cleanedRegex |
|
76 | @regex = new RegExp @cleanedRegex, 'g'+modifiers.replace('g', '') |
76 | @regex = new RegExp @cleanedRegex, 'g'+modifiers.replace('g', '') |
|
77 | @mapping = mapping |
77 | @mapping = mapping |
|
78 | |
78 | |
|
79 | |
79 | |
|
80 | # Executes the pattern's regex and returns the matching values |
80 | # Executes the pattern's regex and returns the matching values |
|
81 | # |
81 | # |
|
82 | # @param [String] str The string to use to execute the pattern |
82 | # @param [String] str The string to use to execute the pattern |
|
83 | # |
83 | # |
|
84 | # @return [Array] The matching values extracted from capturing brackets or null if nothing matched |
84 | # @return [Array] The matching values extracted from capturing brackets or null if nothing matched |
|
85 | # |
85 | # |
|
86 | exec: (str) -> |
86 | exec: (str) -> |
|
87 | @regex.lastIndex = 0 |
87 | @regex.lastIndex = 0 |
|
88 | matches = @regex.exec str |
88 | matches = @regex.exec str |
|
89 | |
89 | |
|
90 | if not matches? |
90 | if not matches? |
|
91 | return null |
91 | return null |
|
92 | |
92 | |
|
93 | if @mapping? |
93 | if @mapping? |
|
94 | for name, index of @mapping |
94 | for name, index of @mapping |
|
95 | matches[name] = matches[index] |
95 | matches[name] = matches[index] |
|
96 | |
96 | |
|
97 | return matches |
97 | return matches |
|
98 | |
98 | |
|
99 | |
99 | |
|
100 | # Tests the pattern's regex |
100 | # Tests the pattern's regex |
|
101 | # |
101 | # |
|
102 | # @param [String] str The string to use to test the pattern |
102 | # @param [String] str The string to use to test the pattern |
|
103 | # |
103 | # |
|
104 | # @return [Boolean] true if the string matched |
104 | # @return [Boolean] true if the string matched |
|
105 | # |
105 | # |
|
106 | test: (str) -> |
106 | test: (str) -> |
|
107 | @regex.lastIndex = 0 |
107 | @regex.lastIndex = 0 |
|
108 | return @regex.test str |
108 | return @regex.test str |
|
109 | |
109 | |
|
110 | |
110 | |
|
111 | # Replaces occurences matching with the pattern's regex with replacement |
111 | # Replaces occurences matching with the pattern's regex with replacement |
|
112 | # |
112 | # |
|
113 | # @param [String] str The source string to perform replacements |
113 | # @param [String] str The source string to perform replacements |
|
114 | # @param [String] replacement The string to use in place of each replaced occurence. |
114 | # @param [String] replacement The string to use in place of each replaced occurence. |
|
115 | # |
115 | # |
|
116 | # @return [String] The replaced string |
116 | # @return [String] The replaced string |
|
117 | # |
117 | # |
|
118 | replace: (str, replacement) -> |
118 | replace: (str, replacement) -> |
|
119 | @regex.lastIndex = 0 |
119 | @regex.lastIndex = 0 |
|
120 | return str.replace @regex, replacement |
120 | return str.replace @regex, replacement |
|
121 | |
121 | |
|
122 | |
122 | |
|
123 | # Replaces occurences matching with the pattern's regex with replacement and |
123 | # Replaces occurences matching with the pattern's regex with replacement and |
|
124 | # get both the replaced string and the number of replaced occurences in the string. |
124 | # get both the replaced string and the number of replaced occurences in the string. |
|
125 | # |
125 | # |
|
126 | # @param [String] str The source string to perform replacements |
126 | # @param [String] str The source string to perform replacements |
|
127 | # @param [String] replacement The string to use in place of each replaced occurence. |
127 | # @param [String] replacement The string to use in place of each replaced occurence. |
|
128 | # @param [Integer] limit The maximum number of occurences to replace (0 means infinite number of occurences) |
128 | # @param [Integer] limit The maximum number of occurences to replace (0 means infinite number of occurences) |
|
129 | # |
129 | # |
|
130 | # @return [Array] A destructurable array containing the replaced string and the number of replaced occurences. For instance: ["my replaced string", 2] |
130 | # @return [Array] A destructurable array containing the replaced string and the number of replaced occurences. For instance: ["my replaced string", 2] |
|
131 | # |
131 | # |
|
132 | replaceAll: (str, replacement, limit = 0) -> |
132 | replaceAll: (str, replacement, limit = 0) -> |
|
133 | @regex.lastIndex = 0 |
133 | @regex.lastIndex = 0 |
|
134 | count = 0 |
134 | count = 0 |
|
135 | while @regex.test(str) and (limit is 0 or count < limit) |
135 | while @regex.test(str) and (limit is 0 or count < limit) |
|
136 | @regex.lastIndex = 0 |
136 | @regex.lastIndex = 0 |
|
137 | str = str.replace @regex, '' |
137 | str = str.replace @regex, replacement |
|
138 | count++ |
138 | count++ |
|
139 | |
139 | |
|
140 | return [str, count] |
140 | return [str, count] |
|
141 | |
141 | |
|
142 | |
142 | |
|
143 | module.exports = Pattern |
143 | module.exports = Pattern |
|
144 | |
144 | |
|
145 | |
145 | |