diff --git a/Foundation.xcodeproj/project.pbxproj b/Foundation.xcodeproj/project.pbxproj index afce7cd277..3fb3fc8b05 100644 --- a/Foundation.xcodeproj/project.pbxproj +++ b/Foundation.xcodeproj/project.pbxproj @@ -189,6 +189,7 @@ 5BF7AEBF1BCD51F9008F214A /* NSURL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BDC3F4A1BCC5DCB00ED97BB /* NSURL.swift */; }; 5BF7AEC01BCD51F9008F214A /* NSUUID.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BDC3F4B1BCC5DCB00ED97BB /* NSUUID.swift */; }; 5BF7AEC11BCD51F9008F214A /* NSValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BDC3F4C1BCC5DCB00ED97BB /* NSValue.swift */; }; + DCC7AF291C10DE57000417E3 /* TestNSRange.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCC7AF271C10DE57000417E3 /* TestNSRange.swift */; }; EA66F6361BEED03E00136161 /* TargetConditionals.h in Headers */ = {isa = PBXBuildFile; fileRef = EA66F6351BEED03E00136161 /* TargetConditionals.h */; settings = {ATTRIBUTES = (Public, ); }; }; EA66F6441BF1619600136161 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA66F6381BF1619600136161 /* main.swift */; }; EA66F6481BF1619600136161 /* NSURLTestData.plist in Resources */ = {isa = PBXBuildFile; fileRef = EA66F63B1BF1619600136161 /* NSURLTestData.plist */; }; @@ -503,6 +504,7 @@ 5BDC3FCF1BCF17E600ED97BB /* NSCFSet.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSCFSet.swift; sourceTree = ""; }; 5BDC405C1BD6D83B00ED97BB /* TestFoundation.app */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = TestFoundation.app; sourceTree = BUILT_PRODUCTS_DIR; }; 5BF7AEC21BCD568D008F214A /* ForSwiftFoundationOnly.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ForSwiftFoundationOnly.h; sourceTree = ""; }; + DCC7AF271C10DE57000417E3 /* TestNSRange.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestNSRange.swift; sourceTree = ""; }; EA313DFC1BE7F2E90060A403 /* CFURLComponents_Internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CFURLComponents_Internal.h; sourceTree = ""; }; EA313DFD1BE7F2E90060A403 /* CFURLComponents_URIParser.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = CFURLComponents_URIParser.c; sourceTree = ""; }; EA313DFE1BE7F2E90060A403 /* CFURLComponents.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = CFURLComponents.c; sourceTree = ""; }; @@ -986,6 +988,7 @@ EA66F65A1BF1976100136161 /* Tests */ = { isa = PBXGroup; children = ( + DCC7AF271C10DE57000417E3 /* TestNSRange.swift */, EA66F63C1BF1619600136161 /* TestNSArray.swift */, EA66F63D1BF1619600136161 /* TestNSDictionary.swift */, EA66F63E1BF1619600136161 /* TestNSIndexSet.swift */, @@ -1678,6 +1681,7 @@ files = ( 525AECED1BF2C9C500D15BB0 /* TestNSFileManager.swift in Sources */, EA66F6501BF1619600136161 /* TestNSNumber.swift in Sources */, + DCC7AF291C10DE57000417E3 /* TestNSRange.swift in Sources */, EA66F6521BF1619600136161 /* TestNSPropertyList.swift in Sources */, EA66F64E1BF1619600136161 /* TestNSIndexSet.swift in Sources */, EA66F6541BF1619600136161 /* TestNSSet.swift in Sources */, diff --git a/Foundation/NSRange.swift b/Foundation/NSRange.swift index 2cbdee73c6..3467218f95 100644 --- a/Foundation/NSRange.swift +++ b/Foundation/NSRange.swift @@ -99,5 +99,29 @@ public func NSStringFromRange(range: NSRange) -> String { } public func NSRangeFromString(aString: String) -> NSRange { - NSUnimplemented() -} \ No newline at end of file + // just by playing around in the REPL, it looks like + // NSRangeFromString just walks through the string finding + // all integers in order, defaulting to 0 if they're not found. + return NSRangeParser.parseRange(aString) +} + +struct NSRangeParser { + // removes all characters that are not decimal digits and commas. + static let decimalDigitsAndCommas: NSCharacterSet = { + let characterSet = NSMutableCharacterSet(bitmapRepresentation: NSCharacterSet.decimalDigitCharacterSet().bitmapRepresentation) + characterSet.addCharactersInString(",") + return characterSet.invertedSet + }() + static func parseRange(string: String) -> NSRange { + var final = NSRange(location: 0, length: 0) + let removeNonDigits = (string as NSString) + .componentsSeparatedByCharactersInSet(NSRangeParser.decimalDigitsAndCommas) + .joinWithSeparator("") + let ints = removeNonDigits.componentsSeparatedByString(",").flatMap { Int($0) } + guard let location = ints.first else { return final } + final.location = location + guard let length = ints.dropFirst().first else { return final } + final.length = length + return final + } +} diff --git a/Foundation/NSString.swift b/Foundation/NSString.swift index 1521ca0f85..6d1a8f8a6b 100644 --- a/Foundation/NSString.swift +++ b/Foundation/NSString.swift @@ -630,11 +630,39 @@ extension NSString { } public func componentsSeparatedByString(separator: String) -> [String] { - NSUnimplemented() + let sepLength = separator.characters.count + var previousSplit = 0 + var components = [String]() + for i in (0.. [String] { - NSUnimplemented() + let worker = self as String + var components = [String]() + var current = "" + for scalar in worker.unicodeScalars { + if separator.characterIsMember(unichar(unicodeScalarLiteral: scalar)) { + components.append(current) + current = "" + } else { + current.append(scalar) + } + } + components.append(current) + return components } public func stringByTrimmingCharactersInSet(set: NSCharacterSet) -> String { diff --git a/TestFoundation/TestNSRange.swift b/TestFoundation/TestNSRange.swift new file mode 100644 index 0000000000..0af3cafd3d --- /dev/null +++ b/TestFoundation/TestNSRange.swift @@ -0,0 +1,51 @@ +// +// TestNSRange.swift +// Foundation +// +// Created by Harlan Haskins on 12/3/15. +// Copyright © 2015 Apple. All rights reserved. +// + +#if DEPLOYMENT_RUNTIME_OBJC || os(Linux) + import Foundation + import XCTest +#else + import SwiftFoundation + import SwiftXCTest +#endif + +extension NSRange: Equatable {} + +public func ==(lhs: NSRange, rhs: NSRange) -> Bool { + return lhs.location == rhs.location && lhs.length == rhs.length +} + +class TestNSRange: XCTestCase { + + var allTests: [(String, () -> ())] { + return [ + ("test_rangeWithValidInput", test_rangeWithValidInput), + ("test_rangesWithInvalidInput", test_rangesWithInvalidInput), + ("test_roundTrip", test_roundTrip) + ] + } + + func test_rangeWithValidInput() { + let practice = NSRangeFromString("{4,5}") + XCTAssertEqual(practice, NSRange(location: 4, length: 5)) + } + + func test_rangesWithInvalidInput() { + XCTAssertEqual(NSRangeFromString("4,5}"), NSRange(location: 4, length: 5)) + XCTAssertEqual(NSRangeFromString("{4,5"), NSRange(location: 4, length: 5)) + XCTAssertEqual(NSRangeFromString("{4,}"), NSRange(location: 4, length: 0)) + XCTAssertEqual(NSRangeFromString(",4}"), NSRange(location: 4, length: 0)) + XCTAssertEqual(NSRangeFromString("4,5"), NSRange(location: 4, length: 5)) + } + + func test_roundTrip() { + let initial = NSRange(location: 4, length: 5) + XCTAssertEqual(NSRangeFromString(NSStringFromRange(initial)), initial) + } + +} diff --git a/TestFoundation/main.swift b/TestFoundation/main.swift index 9bbf59448d..20b4197138 100644 --- a/TestFoundation/main.swift +++ b/TestFoundation/main.swift @@ -20,4 +20,4 @@ internal func testBundle() -> NSBundle { } // For the Swift version of the Foundation tests, we must manually list all test cases here. -XCTMain([TestNSString(), TestNSArray(), TestNSDictionary(), TestNSSet(), TestNSNumber(), TestNSPropertyList(), TestNSURL(), TestNSIndexSet(), TestNSCharacterSet(), TestNSFileManger()]) +XCTMain([TestNSString(), TestNSArray(), TestNSDictionary(), TestNSSet(), TestNSNumber(), TestNSPropertyList(), TestNSURL(), TestNSIndexSet(), TestNSCharacterSet(), TestNSFileManger(), TestNSRange()])