@@ -1544,6 +1544,18 @@ extension NSMutableString {
1544
1544
}
1545
1545
return 0
1546
1546
}
1547
+
1548
+ private static func makeFindResultsRangeIterator( findResults: CFArray , count: Int , backwards: Bool ) -> AnyIterator < NSRange > {
1549
+ var index = 0
1550
+ return AnyIterator < NSRange > ( ) { ( ) -> NSRange ? in
1551
+ defer { index += 1 }
1552
+ if index < count {
1553
+ let rangePtr = CFArrayGetValueAtIndex ( findResults, backwards ? count - index - 1 : index)
1554
+ return NSRange ( rangePtr!. load ( as: CFRange . self) )
1555
+ }
1556
+ return nil
1557
+ }
1558
+ }
1547
1559
1548
1560
public func replaceOccurrences( of target: String , with replacement: String , options: CompareOptions = [ ] , range searchRange: NSRange ) -> Int {
1549
1561
let backwards = options. contains ( . backwards)
@@ -1554,19 +1566,35 @@ extension NSMutableString {
1554
1566
if options. contains ( . regularExpression) {
1555
1567
return _replaceOccurrencesOfRegularExpressionPattern ( target, withTemplate: replacement, options: options, range: searchRange)
1556
1568
}
1557
-
1558
1569
1559
- if let findResults = CFStringCreateArrayWithFindResults ( kCFAllocatorSystemDefault, _cfObject, target. _cfObject, CFRange ( searchRange) , options. _cfValue ( true ) ) {
1560
- let numOccurrences = CFArrayGetCount ( findResults)
1561
- for cnt in 0 ..< numOccurrences {
1562
- let rangePtr = CFArrayGetValueAtIndex ( findResults, backwards ? cnt : numOccurrences - cnt - 1 )
1563
- replaceCharacters ( in: NSRange ( rangePtr!. load ( as: CFRange . self) ) , with: replacement)
1570
+ guard let findResults = CFStringCreateArrayWithFindResults ( kCFAllocatorSystemDefault, _cfObject, target. _cfObject, CFRange ( searchRange) , options. _cfValue ( true ) ) else {
1571
+ return 0
1572
+ }
1573
+ let numOccurrences = CFArrayGetCount ( findResults)
1574
+
1575
+ let rangeIterator = NSMutableString . makeFindResultsRangeIterator ( findResults: findResults, count: numOccurrences, backwards: backwards)
1576
+
1577
+ guard type ( of: self ) == NSMutableString . self else {
1578
+ // If we're dealing with non NSMutableString, mutations must go through `replaceCharacters` (documented behavior)
1579
+ for range in rangeIterator {
1580
+ replaceCharacters ( in: range, with: replacement)
1564
1581
}
1582
+
1565
1583
return numOccurrences
1566
- } else {
1567
- return 0
1568
1584
}
1569
1585
1586
+ var newStorage = Substring ( )
1587
+ var sourceStringCurrentIndex = _storage. startIndex
1588
+ for range in rangeIterator {
1589
+ let matchStartIndex = String . Index ( utf16Offset: range. location, in: _storage)
1590
+ let matchEndIndex = String . Index ( utf16Offset: range. location + range. length, in: _storage)
1591
+ newStorage += _storage [ sourceStringCurrentIndex ..< matchStartIndex]
1592
+ newStorage += replacement
1593
+ sourceStringCurrentIndex = matchEndIndex
1594
+ }
1595
+ newStorage += _storage [ sourceStringCurrentIndex ..< _storage. endIndex]
1596
+ _storage = String ( newStorage)
1597
+ return numOccurrences
1570
1598
}
1571
1599
1572
1600
public func applyTransform( _ transform: String , reverse: Bool , range: NSRange , updatedRange resultingRange: NSRangePointer ? ) -> Bool {
0 commit comments