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 CPStringHashes = new objj_dictionary();
00060
00072 @implementation CPString : CPObject
00073
00074
00075
00076
00077 + (id)alloc
00078 {
00079 return new String;
00080 }
00081
00085 + (id)string
00086 {
00087 return [[self alloc] init];
00088 }
00089
00094 + (id)stringWithHash:(unsigned)aHash
00095 {
00096 var hashString = parseInt(aHash, 10).toString(16);
00097 return "000000".substring(0, MAX(6-hashString.length, 0)) + hashString;
00098 }
00099
00106 + (id)stringWithString:(CPString)aString
00107 {
00108 if (!aString)
00109 [CPException raise:CPInvalidArgumentException
00110 reason:"stringWithString: the string can't be 'nil'"];
00111
00112 return [[self alloc] initWithString:aString];
00113 }
00114
00120 - (id)initWithString:(CPString)aString
00121 {
00122 return String(aString);
00123 }
00124
00130 - (id)initWithFormat:(CPString)format, ...
00131 {
00132 if (!format)
00133 [CPException raise:CPInvalidArgumentException
00134 reason:"initWithFormat: the format can't be 'nil'"];
00135
00136 self = sprintf.apply(this, Array.prototype.slice.call(arguments, 2));
00137 return self;
00138 }
00139
00146 + (id)stringWithFormat:(CPString)format, ...
00147 {
00148 if (!format)
00149 [CPException raise:CPInvalidArgumentException
00150 reason:"initWithFormat: the format can't be 'nil'"];
00151
00152 return sprintf.apply(this, Array.prototype.slice.call(arguments, 2));
00153 }
00154
00158 - (CPString)description
00159 {
00160 return self;
00161 }
00162
00166 - (int)length
00167 {
00168 return length;
00169 }
00170
00175 - (CPString)characterAtIndex:(unsigned)anIndex
00176 {
00177 return charAt(anIndex);
00178 }
00179
00180
00181
00188 - (CPString)stringByAppendingFormat:(CPString)format, ...
00189 {
00190 if (!format)
00191 [CPException raise:CPInvalidArgumentException reason:"initWithFormat: the format can't be 'nil'"];
00192
00193 return self + sprintf.apply(this, Array.prototype.slice.call(arguments, 2));
00194 }
00195
00201 - (CPString)stringByAppendingString:(CPString)aString
00202 {
00203 return self + aString;
00204 }
00205
00218 - (CPString)stringByPaddingToLength:(unsigned)aLength withString:(CPString)aString startingAtIndex:(unsigned)anIndex
00219 {
00220 if (length == aLength)
00221 return self;
00222
00223 if (aLength < length)
00224 return substr(0, aLength);
00225
00226 var string = self,
00227 substring = aString.substring(anIndex),
00228 difference = aLength - length;
00229
00230 while ((difference -= substring.length) >= 0)
00231 string += substring;
00232
00233 if (-difference < substring.length)
00234 string += substring.substring(0, -difference);
00235
00236 return string;
00237 }
00238
00239
00251 - (CPArray)componentsSeparatedByString:(CPString)aString
00252 {
00253 return split(aString);
00254 }
00255
00261 - (CPString)substringFromIndex:(unsigned)anIndex
00262 {
00263 return substr(anIndex);
00264 }
00265
00271 - (CPString)substringWithRange:(CPRange)aRange
00272 {
00273 return substr(aRange.location, aRange.length);
00274 }
00275
00281 - (CPString)substringToIndex:(unsigned)anIndex
00282 {
00283 return substring(0, anIndex);
00284 }
00285
00286
00287
00294 - (CPRange)rangeOfString:(CPString)aString
00295 {
00296 return [self rangeOfString:aString options:0];
00297 }
00298
00316 - (CPRange)rangeOfString:(CPString)aString options:(int)aMask
00317 {
00318 return [self rangeOfString:aString options:aMask range:nil];
00319 }
00320
00339 - (CPRange)rangeOfString:(CPString)aString options:(int)aMask range:(CPrange)aRange
00340 {
00341 var string = (aRange == nil) ? self : [self substringWithRange:aRange],
00342 location = CPNotFound;
00343
00344 if (aMask & CPCaseInsensitiveSearch)
00345 {
00346 string = string.toLowerCase();
00347 aString = aString.toLowerCase();
00348 }
00349
00350 if (aMask & CPBackwardsSearch)
00351 location = string.lastIndexOf(aString, aMask & CPAnchoredSearch ? length - aString.length : 0);
00352 else if (aMask & CPAnchoredSearch)
00353 location = string.substr(0, aString.length).indexOf(aString) != CPNotFound ? 0 : CPNotFound;
00354 else
00355 location = string.indexOf(aString);
00356
00357 return CPMakeRange(location, location == CPNotFound ? 0 : aString.length);
00358 }
00359
00360
00361
00369 - (CPString)stringByReplacingOccurrencesOfString:(CPString)target withString:(CPString)replacement
00370 {
00371 return self.replace(new RegExp(target, "g"), replacement);
00372 }
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383 - (CPString)stringByReplacingOccurrencesOfString:(CPString)target withString:(CPString)replacement options:(int)options range:(CPRange)searchRange
00384 {
00385 var start = substring(0, searchRange.location),
00386 stringSegmentToSearch = substr(searchRange.location, searchRange.length),
00387 end = substring(searchRange.location + searchRange.length, self.length),
00388 regExp;
00389
00390 if (options & CPCaseInsensitiveSearch)
00391 regExp = new RegExp(target, "gi");
00392 else
00393 regExp = new RegExp(target, "g");
00394
00395 return start + '' + stringSegmentToSearch.replace(regExp, replacement) + '' + end;
00396 }
00397
00398
00399
00400
00401
00402
00403
00404
00405 - (CPString)stringByReplacingCharactersInRange:(CPRange)range withString:(CPString)replacement
00406 {
00407 return '' + substring(0, range.location) + replacement + substring(range.location + range.length, self.length);
00408 }
00409
00410
00411
00412
00418 - (CPComparisonResult)compare:(CPString)aString
00419 {
00420 return [self compare:aString options:nil];
00421 }
00422
00423
00424
00425
00426
00427
00428
00429 - (CPComparisonResult)caseInsensitiveCompare:(CPString)aString
00430 {
00431 return [self compare:aString options:CPCaseInsensitiveSearch];
00432 }
00433
00440 - (CPComparisonResult)compare:(CPString)aString options:(int)aMask
00441 {
00442 var lhs = self,
00443 rhs = aString;
00444
00445 if (aMask & CPCaseInsensitiveSearch)
00446 {
00447 lhs = lhs.toLowerCase();
00448 rhs = rhs.toLowerCase();
00449 }
00450
00451 if (lhs < rhs)
00452 return CPOrderedAscending;
00453 else if (lhs > rhs)
00454 return CPOrderedDescending;
00455
00456 return CPOrderedSame;
00457 }
00458
00466 - (CPComparisonResult)compare:(CPString)aString options:(int)aMask range:(CPRange)range
00467 {
00468 var lhs = [self substringWithRange:range],
00469 rhs = aString;
00470
00471 return [lhs compare:rhs options:aMask];
00472 }
00473
00479 - (BOOL)hasPrefix:(CPString)aString
00480 {
00481 return aString && aString != "" && indexOf(aString) == 0;
00482 }
00483
00489 - (BOOL)hasSuffix:(CPString)aString
00490 {
00491 return aString && aString != "" && lastIndexOf(aString) == (length - aString.length);
00492 }
00493
00497 - (BOOL)isEqualToString:(CPString)aString
00498 {
00499 return self == aString;
00500 }
00501
00505 - (unsigned)hash
00506 {
00507 var hash = dictionary_getValue(CPStringHashes, self);
00508
00509 if (!hash)
00510 {
00511 hash = _objj_generateObjectHash();
00512 dictionary_setValue(CPStringHashes, self, hash);
00513 }
00514
00515 return hash;
00516 }
00517
00521 - (CPString)capitalizedString
00522 {
00523 var parts = self.split(/\b/g);
00524 for (var i = 0; i < parts.length; i++)
00525 {
00526 if (i == 0 || (/\s$/).test(parts[i-1]))
00527 parts[i] = parts[i].substring(0, 1).toUpperCase() + parts[i].substring(1).toLowerCase();
00528 else
00529 parts[i] = parts[i].toLowerCase();
00530 }
00531 return parts.join("");
00532 }
00533
00537 - (CPString)lowercaseString
00538 {
00539 return toLowerCase();
00540 }
00541
00545 - (CPString)uppercaseString
00546 {
00547 return toUpperCase();
00548 }
00549
00553 - (double)doubleValue
00554 {
00555 return parseFloat(self, 10);
00556 }
00563 - (BOOL)boolValue
00564 {
00565 var replaceRegExp = new RegExp("^\\s*[\\+,\\-]*0*");
00566 return RegExp("^[Y,y,t,T,1-9]").test(self.replace(replaceRegExp, ''));
00567 }
00568
00572 - (float)floatValue
00573 {
00574 return parseFloat(self, 10);
00575 }
00576
00580 - (int)intValue
00581 {
00582 return parseInt(self, 10);
00583 }
00584
00590 - (CPArray)pathComponents
00591 {
00592 var result = split('/');
00593 if (result[0] === "")
00594 result[0] = "/";
00595 if (result[result.length - 1] === "")
00596 result.pop();
00597 return result;
00598 }
00599
00605 - (CPString)pathExtension
00606 {
00607 return substr(lastIndexOf('.') + 1);
00608 }
00609
00615 - (CPString)lastPathComponent
00616 {
00617 var components = [self pathComponents];
00618 return components[components.length -1];
00619 }
00620
00626 - (CPString)stringByDeletingLastPathComponent
00627 {
00628 var path = self,
00629 start = length - 1;
00630
00631 while (path.charAt(start) === '/')
00632 start--;
00633
00634 path = path.substr(0, path.lastIndexOf('/', start));
00635
00636 if (path === "" && charAt(0) === '/')
00637 return '/';
00638
00639 return path;
00640 }
00641
00642 - (CPString)stringByStandardizingPath
00643 {
00644 return objj_standardize_path(self);
00645 }
00646
00647 - (CPString)copy
00648 {
00649 return new String(self);
00650 }
00651
00652 @end
00653
00654
00655 @implementation CPString (JSON)
00656
00660 + (CPString)JSONFromObject:(JSObject)anObject
00661 {
00662 return CPJSObjectCreateJSON(anObject);
00663 }
00664
00668 - (JSObject)objectFromJSON
00669 {
00670 return CPJSObjectCreateWithJSON(self);
00671 }
00672
00673 @end
00674
00675
00676 @implementation CPString (UUID)
00677
00681 + (CPString)UUID
00682 {
00683 var g = @"";
00684
00685 for(var i = 0; i < 32; i++)
00686 g += FLOOR(RAND() * 0xF).toString(0xF);
00687
00688 return g;
00689 }
00690
00691 @end
00692
00693 String.prototype.isa = CPString;