00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 @import "CPObject.j"
00024 @import "CPException.j"
00025 @import "CPSortDescriptor.j"
00026 @import "CPValue.j"
00027
00028
00034 CPCaseInsensitiveSearch = 1;
00040 CPLiteralSearch = 2;
00046 CPBackwardsSearch = 4;
00051 CPAnchoredSearch = 8;
00057 CPNumericSearch = 64;
00058
00059 var CPStringUIDs = new CFMutableDictionary();
00060
00061 var CPStringRegexSpecialCharacters = [
00062 '/', '.', '*', '+', '?', '|', '$', '^',
00063 '(', ')', '[', ']', '{', '}', '\\'
00064 ],
00065 CPStringRegexEscapeExpression = new RegExp("(\\" + CPStringRegexSpecialCharacters.join("|\\") + ")", 'g'),
00066 CPStringRegexTrimWhitespace = new RegExp("(^\\s+|\\s+$)", 'g');
00067
00081 @implementation CPString : CPObject
00082
00083
00084
00085
00086 + (id)alloc
00087 {
00088 return new String;
00089 }
00090
00094 + (id)string
00095 {
00096 return [[self alloc] init];
00097 }
00098
00103 + (id)stringWithHash:(unsigned)aHash
00104 {
00105 var hashString = parseInt(aHash, 10).toString(16);
00106 return "000000".substring(0, MAX(6-hashString.length, 0)) + hashString;
00107 }
00108
00115 + (id)stringWithString:(CPString)aString
00116 {
00117 if (!aString)
00118 [CPException raise:CPInvalidArgumentException
00119 reason:"stringWithString: the string can't be 'nil'"];
00120
00121 return [[self alloc] initWithString:aString];
00122 }
00123
00129 - (id)initWithString:(CPString)aString
00130 {
00131 return String(aString);
00132 }
00133
00139 - (id)initWithFormat:(CPString)format, ...
00140 {
00141 if (!format)
00142 [CPException raise:CPInvalidArgumentException
00143 reason:"initWithFormat: the format can't be 'nil'"];
00144
00145 self = ObjectiveJ.sprintf.apply(this, Array.prototype.slice.call(arguments, 2));
00146 return self;
00147 }
00148
00155 + (id)stringWithFormat:(CPString)format, ...
00156 {
00157 if (!format)
00158 [CPException raise:CPInvalidArgumentException
00159 reason:"initWithFormat: the format can't be 'nil'"];
00160
00161 return ObjectiveJ.sprintf.apply(this, Array.prototype.slice.call(arguments, 2));
00162 }
00163
00167 - (CPString)description
00168 {
00169 return self;
00170 }
00171
00175 - (int)length
00176 {
00177 return length;
00178 }
00179
00184 - (CPString)characterAtIndex:(unsigned)anIndex
00185 {
00186 return charAt(anIndex);
00187 }
00188
00189
00190
00197 - (CPString)stringByAppendingFormat:(CPString)format, ...
00198 {
00199 if (!format)
00200 [CPException raise:CPInvalidArgumentException reason:"initWithFormat: the format can't be 'nil'"];
00201
00202 return self + ObjectiveJ.sprintf.apply(this, Array.prototype.slice.call(arguments, 2));
00203 }
00204
00210 - (CPString)stringByAppendingString:(CPString)aString
00211 {
00212 return self + aString;
00213 }
00214
00227 - (CPString)stringByPaddingToLength:(unsigned)aLength withString:(CPString)aString startingAtIndex:(unsigned)anIndex
00228 {
00229 if (length == aLength)
00230 return self;
00231
00232 if (aLength < length)
00233 return substr(0, aLength);
00234
00235 var string = self,
00236 substring = aString.substring(anIndex),
00237 difference = aLength - length;
00238
00239 while ((difference -= substring.length) >= 0)
00240 string += substring;
00241
00242 if (-difference < substring.length)
00243 string += substring.substring(0, -difference);
00244
00245 return string;
00246 }
00247
00248
00260 - (CPArray)componentsSeparatedByString:(CPString)aString
00261 {
00262 return split(aString);
00263 }
00264
00270 - (CPString)substringFromIndex:(unsigned)anIndex
00271 {
00272 return substr(anIndex);
00273 }
00274
00280 - (CPString)substringWithRange:(CPRange)aRange
00281 {
00282 return substr(aRange.location, aRange.length);
00283 }
00284
00290 - (CPString)substringToIndex:(unsigned)anIndex
00291 {
00292 return substring(0, anIndex);
00293 }
00294
00295
00296
00303 - (CPRange)rangeOfString:(CPString)aString
00304 {
00305 return [self rangeOfString:aString options:0];
00306 }
00307
00325 - (CPRange)rangeOfString:(CPString)aString options:(int)aMask
00326 {
00327 return [self rangeOfString:aString options:aMask range:nil];
00328 }
00329
00348 - (CPRange)rangeOfString:(CPString)aString options:(int)aMask range:(CPrange)aRange
00349 {
00350 var string = (aRange == nil) ? self : [self substringWithRange:aRange],
00351 location = CPNotFound;
00352
00353 if (aMask & CPCaseInsensitiveSearch)
00354 {
00355 string = string.toLowerCase();
00356 aString = aString.toLowerCase();
00357 }
00358
00359 if (aMask & CPBackwardsSearch)
00360 location = string.lastIndexOf(aString, aMask & CPAnchoredSearch ? length - aString.length : 0);
00361 else if (aMask & CPAnchoredSearch)
00362 location = string.substr(0, aString.length).indexOf(aString) != CPNotFound ? 0 : CPNotFound;
00363 else
00364 location = string.indexOf(aString);
00365
00366 return CPMakeRange(location, location == CPNotFound ? 0 : aString.length);
00367 }
00368
00369
00370
00371 - (CPString)stringByEscapingRegexControlCharacters
00372 {
00373 return self.replace(CPStringRegexEscapeExpression, "\\$1");
00374 }
00375
00383 - (CPString)stringByReplacingOccurrencesOfString:(CPString)target withString:(CPString)replacement
00384 {
00385 return self.replace(new RegExp([target stringByEscapingRegexControlCharacters], "g"), replacement);
00386 }
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397 - (CPString)stringByReplacingOccurrencesOfString:(CPString)target withString:(CPString)replacement options:(int)options range:(CPRange)searchRange
00398 {
00399 var start = substring(0, searchRange.location),
00400 stringSegmentToSearch = substr(searchRange.location, searchRange.length),
00401 end = substring(searchRange.location + searchRange.length, self.length),
00402 target = [target stringByEscapingRegexControlCharacters],
00403 regExp;
00404
00405 if (options & CPCaseInsensitiveSearch)
00406 regExp = new RegExp(target, "gi");
00407 else
00408 regExp = new RegExp(target, "g");
00409
00410 return start + '' + stringSegmentToSearch.replace(regExp, replacement) + '' + end;
00411 }
00412
00413
00414
00415
00416
00417
00418
00419
00420 - (CPString)stringByReplacingCharactersInRange:(CPRange)range withString:(CPString)replacement
00421 {
00422 return '' + substring(0, range.location) + replacement + substring(range.location + range.length, self.length);
00423 }
00424
00428 - (CPString)stringByTrimmingWhitespace
00429 {
00430 return self.replace(CPStringRegexTrimWhitespace, "");
00431 }
00432
00433
00434
00440 - (CPComparisonResult)compare:(CPString)aString
00441 {
00442 return [self compare:aString options:nil];
00443 }
00444
00445
00446
00447
00448
00449
00450
00451 - (CPComparisonResult)caseInsensitiveCompare:(CPString)aString
00452 {
00453 return [self compare:aString options:CPCaseInsensitiveSearch];
00454 }
00455
00462 - (CPComparisonResult)compare:(CPString)aString options:(int)aMask
00463 {
00464 var lhs = self,
00465 rhs = aString;
00466
00467 if (aMask & CPCaseInsensitiveSearch)
00468 {
00469 lhs = lhs.toLowerCase();
00470 rhs = rhs.toLowerCase();
00471 }
00472
00473 if (lhs < rhs)
00474 return CPOrderedAscending;
00475 else if (lhs > rhs)
00476 return CPOrderedDescending;
00477
00478 return CPOrderedSame;
00479 }
00480
00488 - (CPComparisonResult)compare:(CPString)aString options:(int)aMask range:(CPRange)range
00489 {
00490 var lhs = [self substringWithRange:range],
00491 rhs = aString;
00492
00493 return [lhs compare:rhs options:aMask];
00494 }
00495
00501 - (BOOL)hasPrefix:(CPString)aString
00502 {
00503 return aString && aString != "" && indexOf(aString) == 0;
00504 }
00505
00511 - (BOOL)hasSuffix:(CPString)aString
00512 {
00513 return aString && aString != "" && length >= aString.length && lastIndexOf(aString) == (length - aString.length);
00514 }
00515
00519 - (BOOL)isEqualToString:(CPString)aString
00520 {
00521 return self == aString;
00522 }
00523
00527 - (unsigned)UID
00528 {
00529 var UID = CPStringUIDs.valueForKey(self);
00530
00531 if (!UID)
00532 {
00533 UID = objj_generateObjectUID();
00534 CPStringUIDs.setValueForKey(self, UID);
00535 }
00536
00537 return UID + "";
00538 }
00539
00545 - (CPString)commonPrefixWithString:(CPString)aString
00546 {
00547 return [self commonPrefixWithString: aString options: 0];
00548 }
00549
00556 - (CPString)commonPrefixWithString:(CPString)aString options:(int)aMask
00557 {
00558 var len = 0,
00559 lhs = self,
00560 rhs = aString,
00561 min = MIN([lhs length], [rhs length]);
00562
00563 if (aMask & CPCaseInsensitiveSearch)
00564 {
00565 lhs = [lhs lowercaseString];
00566 rhs = [rhs lowercaseString];
00567 }
00568
00569 for (; len < min; len++ )
00570 {
00571 if ( [lhs characterAtIndex:len] !== [rhs characterAtIndex:len] )
00572 break;
00573 }
00574
00575 return [self substringToIndex:len];
00576 }
00577
00581 - (CPString)capitalizedString
00582 {
00583 var parts = self.split(/\b/g);
00584 for (var i = 0; i < parts.length; i++)
00585 {
00586 if (i == 0 || (/\s$/).test(parts[i-1]))
00587 parts[i] = parts[i].substring(0, 1).toUpperCase() + parts[i].substring(1).toLowerCase();
00588 else
00589 parts[i] = parts[i].toLowerCase();
00590 }
00591 return parts.join("");
00592 }
00593
00597 - (CPString)lowercaseString
00598 {
00599 return toLowerCase();
00600 }
00601
00605 - (CPString)uppercaseString
00606 {
00607 return toUpperCase();
00608 }
00609
00613 - (double)doubleValue
00614 {
00615 return parseFloat(self, 10);
00616 }
00623 - (BOOL)boolValue
00624 {
00625 var replaceRegExp = new RegExp("^\\s*[\\+,\\-]*0*");
00626 return RegExp("^[Y,y,t,T,1-9]").test(self.replace(replaceRegExp, ''));
00627 }
00628
00632 - (float)floatValue
00633 {
00634 return parseFloat(self, 10);
00635 }
00636
00640 - (int)intValue
00641 {
00642 return parseInt(self, 10);
00643 }
00644
00650 - (CPArray)pathComponents
00651 {
00652 var result = split('/');
00653 if (result[0] === "")
00654 result[0] = "/";
00655 if (result[result.length - 1] === "")
00656 result.pop();
00657 return result;
00658 }
00659
00665 - (CPString)pathExtension
00666 {
00667 return substr(lastIndexOf('.') + 1);
00668 }
00669
00675 - (CPString)lastPathComponent
00676 {
00677 var components = [self pathComponents];
00678 return components[components.length -1];
00679 }
00680
00686 - (CPString)stringByDeletingLastPathComponent
00687 {
00688 var path = self,
00689 start = length - 1;
00690
00691 while (path.charAt(start) === '/')
00692 start--;
00693
00694 path = path.substr(0, path.lastIndexOf('/', start));
00695
00696 if (path === "" && charAt(0) === '/')
00697 return '/';
00698
00699 return path;
00700 }
00701
00702 - (CPString)stringByStandardizingPath
00703 {
00704 return objj_standardize_path(self);
00705 }
00706
00707 - (CPString)copy
00708 {
00709 return new String(self);
00710 }
00711
00712 @end
00713
00714
00715 @implementation CPString (JSON)
00716
00720 + (CPString)JSONFromObject:(JSObject)anObject
00721 {
00722 return JSON.stringify(anObject);
00723 }
00724
00728 - (JSObject)objectFromJSON
00729 {
00730 return JSON.parse(self);
00731 }
00732
00733 @end
00734
00735
00736 @implementation CPString (UUID)
00737
00741 + (CPString)UUID
00742 {
00743 var g = @"";
00744
00745 for(var i = 0; i < 32; i++)
00746 g += FLOOR(RAND() * 0xF).toString(0xF);
00747
00748 return g;
00749 }
00750
00751 @end
00752
00753 String.prototype.isa = CPString;