|
1 /* |
|
2 Copyright (c) 2006 Lawrence Oluyede <l.oluyede@gmail.com> |
|
3 |
|
4 Permission is hereby granted, free of charge, to any person obtaining a copy |
|
5 of this software and associated documentation files (the "Software"), to deal |
|
6 in the Software without restriction, including without limitation the rights |
|
7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|
8 copies of the Software, and to permit persons to whom the Software is |
|
9 furnished to do so, subject to the following conditions: |
|
10 |
|
11 The above copyright notice and this permission notice shall be included in all |
|
12 copies or substantial portions of the Software. |
|
13 |
|
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|
19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
|
20 SOFTWARE. |
|
21 */ |
|
22 |
|
23 /* |
|
24 startsWith(str, prefix[, start[, end]]) -> bool |
|
25 |
|
26 Return true if str ends with the specified prefix, false otherwise. |
|
27 With optional start, test str beginning at that position. |
|
28 With optional end, stop comparing str at that position. |
|
29 prefix can also be an array of strings to try. |
|
30 */ |
|
31 |
|
32 var EXPORTED_SYMBOLS = ['startsWith', 'endsWith']; |
|
33 |
|
34 function startsWith(str, prefix, start, end) { |
|
35 if (arguments.length < 2) { |
|
36 throw new TypeError('startsWith() requires at least 2 arguments'); |
|
37 } |
|
38 |
|
39 // check if start and end are null/undefined or a 'number' |
|
40 if ((start == null) || (isNaN(new Number(start)))) { |
|
41 start = 0; |
|
42 } |
|
43 if ((end == null) || (isNaN(new Number(end)))) { |
|
44 end = Number.MAX_VALUE; |
|
45 } |
|
46 |
|
47 // if it's an array |
|
48 if (typeof prefix == "object") { |
|
49 for (var i = 0, j = prefix.length; i < j; i++) { |
|
50 var res = _stringTailMatch(str, prefix[i], start, end, true); |
|
51 if (res) { |
|
52 return true; |
|
53 } |
|
54 } |
|
55 return false; |
|
56 } |
|
57 |
|
58 return _stringTailMatch(str, prefix, start, end, true); |
|
59 } |
|
60 |
|
61 /* |
|
62 endsWith(str, suffix[, start[, end]]) -> bool |
|
63 |
|
64 Return true if str ends with the specified suffix, false otherwise. |
|
65 With optional start, test str beginning at that position. |
|
66 With optional end, stop comparing str at that position. |
|
67 suffix can also be an array of strings to try. |
|
68 */ |
|
69 function endsWith(str, suffix, start, end) { |
|
70 if (arguments.length < 2) { |
|
71 throw new TypeError('endsWith() requires at least 2 arguments'); |
|
72 } |
|
73 |
|
74 // check if start and end are null/undefined or a 'number' |
|
75 if ((start == null) || (isNaN(new Number(start)))) { |
|
76 start = 0; |
|
77 } |
|
78 if ((end == null) || (isNaN(new Number(end)))) { |
|
79 end = Number.MAX_VALUE; |
|
80 } |
|
81 |
|
82 // if it's an array |
|
83 if (typeof suffix == "object") { |
|
84 for (var i = 0, j = suffix.length; i < j; i++) { |
|
85 var res = _stringTailMatch(str, suffix[i], start, end, false); |
|
86 if (res) { |
|
87 return true; |
|
88 } |
|
89 } |
|
90 return false; |
|
91 } |
|
92 |
|
93 return _stringTailMatch(str, suffix, start, end, false); |
|
94 } |
|
95 |
|
96 /* |
|
97 Matches the end (direction == false) or start (direction == true) of str |
|
98 against substr, using the start and end arguments. Returns false |
|
99 if not found and true if found. |
|
100 */ |
|
101 function _stringTailMatch(str, substr, start, end, fromStart) { |
|
102 var len = str.length; |
|
103 var slen = substr.length; |
|
104 |
|
105 var indices = _adjustIndices(start, end, len); |
|
106 start = indices[0]; end = indices[1]; len = indices[2]; |
|
107 |
|
108 if (fromStart) { |
|
109 if (start + slen > len) { |
|
110 return false; |
|
111 } |
|
112 } else { |
|
113 if (end - start < slen || start > len) { |
|
114 return false; |
|
115 } |
|
116 if (end - slen > start) { |
|
117 start = end - slen; |
|
118 } |
|
119 } |
|
120 |
|
121 if (end - start >= slen) { |
|
122 return str.substr(start, slen) == substr; |
|
123 } |
|
124 return false; |
|
125 } |
|
126 |
|
127 function _adjustIndices(start, end, len) |
|
128 { |
|
129 if (end > len) { |
|
130 end = len; |
|
131 } else if (end < 0) { |
|
132 end += len; |
|
133 } |
|
134 |
|
135 if (end < 0) { |
|
136 end = 0; |
|
137 } |
|
138 if (start < 0) { |
|
139 start += len; |
|
140 } |
|
141 if (start < 0) { |
|
142 start = 0; |
|
143 } |
|
144 |
|
145 return [start, end, len]; |
|
146 } |