@@ -1130,7 +1130,7 @@ extension NSString {
1130
1130
}
1131
1131
return " "
1132
1132
}
1133
-
1133
+
1134
1134
open func replacingOccurrences( of target: String , with replacement: String , options: CompareOptions = [ ] , range searchRange: NSRange ) -> String {
1135
1135
if options. contains ( . regularExpression) {
1136
1136
return _stringByReplacingOccurrencesOfRegularExpressionPattern ( target, withTemplate: replacement, options: options, range: searchRange)
@@ -1452,6 +1452,18 @@ extension NSMutableString {
1452
1452
}
1453
1453
return 0
1454
1454
}
1455
+
1456
+ private static func makeFindResultsRangeIterator( findResults: CFArray , count: Int , backwards: Bool ) -> AnyIterator < NSRange > {
1457
+ var index = 0
1458
+ return AnyIterator < NSRange > ( ) { ( ) -> NSRange ? in
1459
+ defer { index += 1 }
1460
+ if index < count {
1461
+ let rangePtr = CFArrayGetValueAtIndex ( findResults, backwards ? count - index - 1 : index)
1462
+ return NSRange ( rangePtr!. load ( as: CFRange . self) )
1463
+ }
1464
+ return nil
1465
+ }
1466
+ }
1455
1467
1456
1468
public func replaceOccurrences( of target: String , with replacement: String , options: CompareOptions = [ ] , range searchRange: NSRange ) -> Int {
1457
1469
let backwards = options. contains ( . backwards)
@@ -1462,19 +1474,35 @@ extension NSMutableString {
1462
1474
if options. contains ( . regularExpression) {
1463
1475
return _replaceOccurrencesOfRegularExpressionPattern ( target, withTemplate: replacement, options: options, range: searchRange)
1464
1476
}
1465
-
1466
1477
1467
- if let findResults = CFStringCreateArrayWithFindResults ( kCFAllocatorSystemDefault, _cfObject, target. _cfObject, CFRange ( searchRange) , options. _cfValue ( true ) ) {
1468
- let numOccurrences = CFArrayGetCount ( findResults)
1469
- for cnt in 0 ..< numOccurrences {
1470
- let rangePtr = CFArrayGetValueAtIndex ( findResults, backwards ? cnt : numOccurrences - cnt - 1 )
1471
- replaceCharacters ( in: NSRange ( rangePtr!. load ( as: CFRange . self) ) , with: replacement)
1478
+ guard let findResults = CFStringCreateArrayWithFindResults ( kCFAllocatorSystemDefault, _cfObject, target. _cfObject, CFRange ( searchRange) , options. _cfValue ( true ) ) else {
1479
+ return 0
1480
+ }
1481
+ let numOccurrences = CFArrayGetCount ( findResults)
1482
+
1483
+ let rangeIterator = NSMutableString . makeFindResultsRangeIterator ( findResults: findResults, count: numOccurrences, backwards: backwards)
1484
+
1485
+ guard type ( of: self ) == NSMutableString . self else {
1486
+ // If we're dealing with non NSMutableString, mutations must go through `replaceCharacters` (documented behavior)
1487
+ for range in rangeIterator {
1488
+ replaceCharacters ( in: range, with: replacement)
1472
1489
}
1490
+
1473
1491
return numOccurrences
1474
- } else {
1475
- return 0
1476
1492
}
1477
1493
1494
+ var newStorage = Substring ( )
1495
+ var sourceStringCurrentIndex = _storage. startIndex
1496
+ for range in rangeIterator {
1497
+ let matchStartIndex = String . Index ( utf16Offset: range. location, in: _storage)
1498
+ let matchEndIndex = String . Index ( utf16Offset: range. location + range. length, in: _storage)
1499
+ newStorage += _storage [ sourceStringCurrentIndex ..< matchStartIndex]
1500
+ newStorage += replacement
1501
+ sourceStringCurrentIndex = matchEndIndex
1502
+ }
1503
+ newStorage += _storage [ sourceStringCurrentIndex ..< _storage. endIndex]
1504
+ _storage = String ( newStorage)
1505
+ return numOccurrences
1478
1506
}
1479
1507
1480
1508
public func applyTransform( _ transform: String , reverse: Bool , range: NSRange , updatedRange resultingRange: NSRangePointer ? ) -> Bool {
0 commit comments