Skip to content

Commit 1f2db58

Browse files
authored
Merge pull request #796 from abl/sr-3448
2 parents 396673b + 90c976b commit 1f2db58

File tree

2 files changed

+43
-4
lines changed

2 files changed

+43
-4
lines changed

Foundation/NSString.swift

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1272,10 +1272,9 @@ open class NSMutableString : NSString {
12721272
NSRequiresConcreteImplementation()
12731273
}
12741274

1275-
// this is incorrectly calculated for grapheme clusters that have a size greater than a single unichar
1276-
let start = _storage.startIndex
1277-
let min = _storage.index(start, offsetBy: range.location)
1278-
let max = _storage.index(start, offsetBy: range.location + range.length)
1275+
let start = _storage.utf16.startIndex
1276+
let min = _storage.utf16.index(start, offsetBy: range.location).samePosition(in: _storage)!
1277+
let max = _storage.utf16.index(start, offsetBy: range.location + range.length).samePosition(in: _storage)!
12791278
_storage.replaceSubrange(min..<max, with: aString)
12801279
}
12811280

TestFoundation/TestNSString.swift

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ class TestNSString : XCTestCase {
9393
("test_PrefixSuffix", test_PrefixSuffix),
9494
("test_utf16StringRangeCount", test_StringUTF16ViewIndexStrideableRange),
9595
("test_reflection", { _ in test_reflection }),
96+
("test_replacingOccurrences", test_replacingOccurrences),
9697
]
9798
}
9899

@@ -1229,3 +1230,42 @@ extension TestNSString {
12291230

12301231
func test_reflection() {
12311232
}
1233+
1234+
extension TestNSString {
1235+
func test_replacingOccurrences() {
1236+
let testPrefix = "ab"
1237+
let testSuffix = "cd"
1238+
let testEmoji = "\u{1F468}\u{200D}\u{1F469}\u{200D}\u{1F467}\u{200D}\u{1F466}"
1239+
let testString = testPrefix + testEmoji + testSuffix
1240+
1241+
let testReplacement = "xyz"
1242+
let testReplacementEmoji = "\u{01F468}\u{200D}\u{002764}\u{00FE0F}\u{200D}\u{01F48B}\u{200D}\u{01F468}"
1243+
1244+
let noChange = testString.replacingOccurrences(of: testReplacement, with: "")
1245+
XCTAssertEqual(noChange, testString)
1246+
1247+
let removePrefix = testString.replacingOccurrences(of: testPrefix, with: "")
1248+
XCTAssertEqual(removePrefix, testEmoji + testSuffix)
1249+
let replacePrefix = testString.replacingOccurrences(of: testPrefix, with: testReplacement)
1250+
XCTAssertEqual(replacePrefix, testReplacement + testEmoji + testSuffix)
1251+
1252+
let removeSuffix = testString.replacingOccurrences(of: testSuffix, with: "")
1253+
XCTAssertEqual(removeSuffix, testPrefix + testEmoji)
1254+
let replaceSuffix = testString.replacingOccurrences(of: testSuffix, with: testReplacement)
1255+
XCTAssertEqual(replaceSuffix, testPrefix + testEmoji + testReplacement)
1256+
1257+
let removeMultibyte = testString.replacingOccurrences(of: testEmoji, with: "")
1258+
XCTAssertEqual(removeMultibyte, testPrefix + testSuffix)
1259+
let replaceMultibyte = testString.replacingOccurrences(of: testEmoji, with: testReplacement)
1260+
XCTAssertEqual(replaceMultibyte, testPrefix + testReplacement + testSuffix)
1261+
1262+
let replaceMultibyteWithMultibyte = testString.replacingOccurrences(of: testEmoji, with: testReplacementEmoji)
1263+
XCTAssertEqual(replaceMultibyteWithMultibyte, testPrefix + testReplacementEmoji + testSuffix)
1264+
1265+
let replacePrefixWithMultibyte = testString.replacingOccurrences(of: testPrefix, with: testReplacementEmoji)
1266+
XCTAssertEqual(replacePrefixWithMultibyte, testReplacementEmoji + testEmoji + testSuffix)
1267+
1268+
let replaceSuffixWithMultibyte = testString.replacingOccurrences(of: testSuffix, with: testReplacementEmoji)
1269+
XCTAssertEqual(replaceSuffixWithMultibyte, testPrefix + testEmoji + testReplacementEmoji)
1270+
}
1271+
}

0 commit comments

Comments
 (0)