1 |
|
2 | Pattern = require './Pattern'
|
3 |
|
4 |
|
5 |
|
6 | class Utils
|
7 |
|
8 | @REGEX_LEFT_TRIM_BY_CHAR: {}
|
9 | @REGEX_RIGHT_TRIM_BY_CHAR: {}
|
10 | @REGEX_SPACES: /\s+/g
|
11 | @REGEX_DIGITS: /^\d+$/
|
12 | @REGEX_OCTAL: /[^0-7]/gi
|
13 | @REGEX_HEXADECIMAL: /[^a-f0-9]/gi
|
14 |
|
15 |
|
16 | @PATTERN_DATE: new Pattern '^'+
|
17 | '(?<year>[0-9][0-9][0-9][0-9])'+
|
18 | '-(?<month>[0-9][0-9]?)'+
|
19 | '-(?<day>[0-9][0-9]?)'+
|
20 | '(?:(?:[Tt]|[ \t]+)'+
|
21 | '(?<hour>[0-9][0-9]?)'+
|
22 | ':(?<minute>[0-9][0-9])'+
|
23 | ':(?<second>[0-9][0-9])'+
|
24 | '(?:\.(?<fraction>[0-9]*))?'+
|
25 | '(?:[ \t]*(?<tz>Z|(?<tz_sign>[-+])(?<tz_hour>[0-9][0-9]?)'+
|
26 | '(?::(?<tz_minute>[0-9][0-9]))?))?)?'+
|
27 | '$', 'i'
|
28 |
|
29 |
|
30 | @LOCAL_TIMEZONE_OFFSET: new Date().getTimezoneOffset() * 60 * 1000
|
31 |
|
32 |
|
33 |
|
34 |
|
35 |
|
36 |
|
37 |
|
38 |
|
39 | @trim: (str, _char = '\\s') ->
|
40 | return str.trim()
|
41 | regexLeft = @REGEX_LEFT_TRIM_BY_CHAR[_char]
|
42 | unless regexLeft?
|
43 | @REGEX_LEFT_TRIM_BY_CHAR[_char] = regexLeft = new RegExp '^'+_char+''+_char+'*'
|
44 | regexLeft.lastIndex = 0
|
45 | regexRight = @REGEX_RIGHT_TRIM_BY_CHAR[_char]
|
46 | unless regexRight?
|
47 | @REGEX_RIGHT_TRIM_BY_CHAR[_char] = regexRight = new RegExp _char+''+_char+'*$'
|
48 | regexRight.lastIndex = 0
|
49 | return str.replace(regexLeft, '').replace(regexRight, '')
|
50 |
|
51 |
|
52 |
|
53 |
|
54 |
|
55 |
|
56 |
|
57 |
|
58 |
|
59 | @ltrim: (str, _char = '\\s') ->
|
60 | regexLeft = @REGEX_LEFT_TRIM_BY_CHAR[_char]
|
61 | unless regexLeft?
|
62 | @REGEX_LEFT_TRIM_BY_CHAR[_char] = regexLeft = new RegExp '^'+_char+''+_char+'*'
|
63 | regexLeft.lastIndex = 0
|
64 | return str.replace(regexLeft, '')
|
65 |
|
66 |
|
67 |
|
68 |
|
69 |
|
70 |
|
71 |
|
72 |
|
73 |
|
74 | @rtrim: (str, _char = '\\s') ->
|
75 | regexRight = @REGEX_RIGHT_TRIM_BY_CHAR[_char]
|
76 | unless regexRight?
|
77 | @REGEX_RIGHT_TRIM_BY_CHAR[_char] = regexRight = new RegExp _char+''+_char+'*$'
|
78 | regexRight.lastIndex = 0
|
79 | return str.replace(regexRight, '')
|
80 |
|
81 |
|
82 |
|
83 |
|
84 |
|
85 |
|
86 |
|
87 |
|
88 | @isEmpty: (value) ->
|
89 | return not(value) or value is '' or value is '0' or (value instanceof Array and value.length is 0)
|
90 |
|
91 |
|
92 |
|
93 |
|
94 |
|
95 |
|
96 |
|
97 |
|
98 |
|
99 |
|
100 |
|
101 | @subStrCount: (string, subString, start, length) ->
|
102 | c = 0
|
103 |
|
104 | string = '' + string
|
105 | subString = '' + subString
|
106 |
|
107 | if start?
|
108 | string = string[start..]
|
109 | if length?
|
110 | string = string[0...length]
|
111 |
|
112 | len = string.length
|
113 | sublen = subString.length
|
114 | for i in [0...len]
|
115 | if subString is string[i...sublen]
|
116 | c++
|
117 | i += sublen - 1
|
118 |
|
119 | return c
|
120 |
|
121 |
|
122 |
|
123 |
|
124 |
|
125 |
|
126 |
|
127 |
|
128 | @isDigits: (input) ->
|
129 | @REGEX_DIGITS.lastIndex = 0
|
130 | return @REGEX_DIGITS.test input
|
131 |
|
132 |
|
133 |
|
134 |
|
135 |
|
136 |
|
137 |
|
138 |
|
139 | @octDec: (input) ->
|
140 | @REGEX_OCTAL.lastIndex = 0
|
141 | return parseInt((input+'').replace(@REGEX_OCTAL, ''), 8)
|
142 |
|
143 |
|
144 |
|
145 |
|
146 |
|
147 |
|
148 |
|
149 |
|
150 | @hexDec: (input) ->
|
151 | @REGEX_HEXADECIMAL.lastIndex = 0
|
152 | input = @trim(input)
|
153 | if (input+'')[0...2] is '0x' then input = (input+'')[2..]
|
154 | return parseInt((input+'').replace(@REGEX_HEXADECIMAL, ''), 16)
|
155 |
|
156 |
|
157 |
|
158 |
|
159 |
|
160 |
|
161 |
|
162 |
|
163 | @utf8chr: (c) ->
|
164 | ch = String.fromCharCode
|
165 | if 0x80 > (c %= 0x200000)
|
166 | return ch(c)
|
167 | if 0x800 > c
|
168 | return ch(0xC0 | c>>6) + ch(0x80 | c & 0x3F)
|
169 | if 0x10000 > c
|
170 | return ch(0xE0 | c>>12) + ch(0x80 | c>>6 & 0x3F) + ch(0x80 | c & 0x3F)
|
171 |
|
172 | return ch(0xF0 | c>>18) + ch(0x80 | c>>12 & 0x3F) + ch(0x80 | c>>6 & 0x3F) + ch(0x80 | c & 0x3F)
|
173 |
|
174 |
|
175 |
|
176 |
|
177 |
|
178 |
|
179 |
|
180 |
|
181 |
|
182 | @parseBoolean: (input, strict = true) ->
|
183 | if typeof(input) is 'string'
|
184 | lowerInput = input.toLowerCase()
|
185 | if not strict
|
186 | if lowerInput is 'no' then return false
|
187 | if lowerInput is '0' then return false
|
188 | if lowerInput is 'false' then return false
|
189 | if lowerInput is '' then return false
|
190 | return true
|
191 | return !!input
|
192 |
|
193 |
|
194 |
|
195 |
|
196 |
|
197 |
|
198 |
|
199 |
|
200 |
|
201 | @isNumeric: (input) ->
|
202 | @REGEX_SPACES.lastIndex = 0
|
203 | return typeof(input) is 'number' or typeof(input) is 'string' and !isNaN(input) and input.replace(@REGEX_SPACES, '') isnt ''
|
204 |
|
205 |
|
206 |
|
207 |
|
208 |
|
209 |
|
210 |
|
211 |
|
212 | @stringToDate: (str) ->
|
213 | unless str?.length
|
214 | return null
|
215 |
|
216 |
|
217 | info = @PATTERN_DATE.exec str
|
218 | unless info
|
219 | return null
|
220 |
|
221 |
|
222 | year = parseInt info.year, 10
|
223 | month = parseInt(info.month, 10) - 1
|
224 | day = parseInt info.day, 10
|
225 |
|
226 |
|
227 | unless info.hour?
|
228 | date = new Date Date.UTC(year, month, day)
|
229 | return date
|
230 |
|
231 |
|
232 | hour = parseInt info.hour, 10
|
233 | minute = parseInt info.minute, 10
|
234 | second = parseInt info.second, 10
|
235 |
|
236 |
|
237 | if info.fraction?
|
238 | fraction = info.fraction[0...3]
|
239 | while fraction.length < 3
|
240 | fraction += '0'
|
241 | fraction = parseInt fraction, 10
|
242 | else
|
243 | fraction = 0
|
244 |
|
245 |
|
246 | if info.tz?
|
247 | tz_hour = parseInt info.tz_hour, 10
|
248 | if info.tz_minute?
|
249 | tz_minute = parseInt info.tz_minute, 10
|
250 | else
|
251 | tz_minute = 0
|
252 |
|
253 |
|
254 | tz_offset = (tz_hour * 60 + tz_minute) * 60000
|
255 | if '-' is info.tz_sign
|
256 | tz_offset *= -1
|
257 |
|
258 |
|
259 | date = new Date Date.UTC(year, month, day, hour, minute, second, fraction)
|
260 | if tz_offset
|
261 | date.setTime date.getTime() + tz_offset
|
262 |
|
263 | return date
|
264 |
|
265 |
|
266 |
|
267 |
|
268 |
|
269 |
|
270 |
|
271 |
|
272 |
|
273 | @strRepeat: (str, number) ->
|
274 | res = ''
|
275 | i = 0
|
276 | while i < number
|
277 | res += str
|
278 | i++
|
279 | return res
|
280 |
|
281 |
|
282 |
|
283 |
|
284 |
|
285 |
|
286 |
|
287 |
|
288 |
|
289 | @getStringFromFile: (path, callback = null) ->
|
290 | xhr = null
|
291 | if window?
|
292 | if window.XMLHttpRequest
|
293 | xhr = new XMLHttpRequest()
|
294 | else if window.ActiveXObject
|
295 | for name in ["Msxml2.XMLHTTP.6.0", "Msxml2.XMLHTTP.3.0", "Msxml2.XMLHTTP", "Microsoft.XMLHTTP"]
|
296 | try
|
297 | xhr = new ActiveXObject(name)
|
298 |
|
299 | if xhr?
|
300 |
|
301 | if callback?
|
302 |
|
303 | xhr.onreadystatechange = ->
|
304 | if xhr.readyState is 4
|
305 | if xhr.status is 200 or xhr.status is 0
|
306 | callback(xhr.responseText)
|
307 | else
|
308 | callback(null)
|
309 | xhr.open 'GET', path, true
|
310 | xhr.send null
|
311 |
|
312 | else
|
313 |
|
314 | xhr.open 'GET', path, false
|
315 | xhr.send null
|
316 |
|
317 | if xhr.status is 200 or xhr.status == 0
|
318 | return xhr.responseText
|
319 |
|
320 | return null
|
321 | else
|
322 |
|
323 | req = require
|
324 | fs = req('fs')
|
325 | if callback?
|
326 |
|
327 | fs.readFile path, (err, data) ->
|
328 | if err
|
329 | callback null
|
330 | else
|
331 | callback String(data)
|
332 |
|
333 | else
|
334 |
|
335 | data = fs.readFileSync path
|
336 | if data?
|
337 | return String(data)
|
338 | return null
|
339 |
|
340 |
|
341 |
|
342 | module.exports = Utils
|