From d1e195b57614b96526b8d88a11933e1d606b2831 Mon Sep 17 00:00:00 2001 From: Ben Leggiero Date: Wed, 20 May 2020 11:13:42 -0600 Subject: [PATCH] Added subscript using `NSRange` --- .../String + Integer access.swift | 42 +++++++++++++++++++ .../StringIntegerAccessTests.swift | 17 ++++++++ 2 files changed, 59 insertions(+) diff --git a/Sources/StringIntegerAccess/String + Integer access.swift b/Sources/StringIntegerAccess/String + Integer access.swift index e3188c4..25ec965 100644 --- a/Sources/StringIntegerAccess/String + Integer access.swift +++ b/Sources/StringIntegerAccess/String + Integer access.swift @@ -127,3 +127,45 @@ public extension StringProtocol { self[PartialRangeThrough(index(range.upperBound))] } } + + + +#if canImport(ObjectiveC) // NSRange seems to only exist on platforms where there's Obj-C +import Foundation + + + +public extension StringProtocol { + + /// Allows you to subscript a string with a `NSRange` + /// + /// These are equivalent: + /// ``` + /// let mySubstring: Substring? + /// if range.length >= 0, + /// let range = Range(nsRange, in: myString) + /// { + /// mySubstring = myString[range] + /// } + /// else { + /// mySubstring = nil + /// } + /// ``` + /// ``` + /// let mySubstring = myString[nsRange] + /// ``` + /// + /// - Parameter range: A range of valid indices of characters in the string. `location` must be less than `count` + /// (exclusive), and `length` must be less than `count` (inclusive). If `length` is longer than + /// `count`, or if `location` pushes the upper bound outside this string, or if `length` is + /// negative, this returns `nil`. + /// - Returns: The characters at the given index-range in this string + @inlinable + @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) + subscript(_ range: NSRange) -> SubSequence? { + return range.length < 0 + ? nil + : Range(range, in: self).map { self[$0] } + } +} +#endif diff --git a/Tests/StringIntegerAccessTests/StringIntegerAccessTests.swift b/Tests/StringIntegerAccessTests/StringIntegerAccessTests.swift index f7d6b33..cd67588 100644 --- a/Tests/StringIntegerAccessTests/StringIntegerAccessTests.swift +++ b/Tests/StringIntegerAccessTests/StringIntegerAccessTests.swift @@ -1,6 +1,8 @@ import XCTest @testable import StringIntegerAccess + + final class StringIntegerAccessTests: XCTestCase { func testGetCharacterWithIntSubscript() { XCTAssertEqual("Hello, World!"[0], "H") @@ -11,6 +13,7 @@ final class StringIntegerAccessTests: XCTestCase { func testGetSubstringWithIntClosedRangeSubscript() { + XCTAssertEqual("Hello, World!"[0...12], "Hello, World!") XCTAssertEqual("Hello, World!"[0...1], "He") XCTAssertEqual("Hello, World!"[1...5], "ello,") XCTAssertEqual("Hello, World!"[12...12], "!") @@ -19,6 +22,7 @@ final class StringIntegerAccessTests: XCTestCase { func testGetSubstringWithIntRangeSubscript() { + XCTAssertEqual("Hello, World!"[0..<13], "Hello, World!") XCTAssertEqual("Hello, World!"[0..<1], "H") XCTAssertEqual("Hello, World!"[1..<5], "ello") XCTAssertEqual("Hello, World!"[12..<12], "") @@ -53,6 +57,19 @@ final class StringIntegerAccessTests: XCTestCase { XCTAssertEqual("Hello, World!"[...12], "Hello, World!") } + + @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) + func testGetSubstringWithNSRangeSubscript() { + XCTAssertEqual("Hello, World!"[NSRange(location: 0, length: 13)], "Hello, World!") + XCTAssertEqual("Hello, World!"[NSRange(location: 0, length: 1)], "H") + XCTAssertEqual("Hello, World!"[NSRange(location: 1, length: 4)], "ello") + XCTAssertEqual("Hello, World!"[NSRange(location: 12, length: 0)], "") + XCTAssertEqual("Hello, World!"[NSRange(location: 11, length: 1)], "d") + XCTAssertEqual("Hello, World!"[NSRange(location: 11, length: 2)], "d!") + XCTAssertNil("Hello, World!"[NSRange(location: 5, length: -5)]) + XCTAssertNil("Hello, World!"[NSRange(location: 11, length: 999)]) + } + static var allTests = [ ("testGetCharacterWithIntSubscript", testGetCharacterWithIntSubscript),