@@ -1130,7 +1130,7 @@ extension NSString {
11301130 }
11311131 return " "
11321132 }
1133-
1133+
11341134 open func replacingOccurrences( of target: String , with replacement: String , options: CompareOptions = [ ] , range searchRange: NSRange ) -> String {
11351135 if options. contains ( . regularExpression) {
11361136 return _stringByReplacingOccurrencesOfRegularExpressionPattern ( target, withTemplate: replacement, options: options, range: searchRange)
@@ -1462,19 +1462,38 @@ extension NSMutableString {
14621462 if options. contains ( . regularExpression) {
14631463 return _replaceOccurrencesOfRegularExpressionPattern ( target, withTemplate: replacement, options: options, range: searchRange)
14641464 }
1465-
14661465
1467- if let findResults = CFStringCreateArrayWithFindResults ( kCFAllocatorSystemDefault, _cfObject, target. _cfObject, CFRange ( searchRange) , options. _cfValue ( true ) ) {
1468- let numOccurrences = CFArrayGetCount ( findResults)
1466+ guard let findResults = CFStringCreateArrayWithFindResults ( kCFAllocatorSystemDefault, _cfObject, target. _cfObject, CFRange ( searchRange) , options. _cfValue ( true ) ) else {
1467+ return 0
1468+ }
1469+ let numOccurrences = CFArrayGetCount ( findResults)
1470+
1471+ return withExtendedLifetime ( findResults) {
1472+ guard type ( of: self ) == NSMutableString . self else {
1473+ // If we're dealing with non NSMutableString, mutations must go through `replaceCharacters` (documented behavior)
1474+ for cnt in 0 ..< numOccurrences {
1475+ let rangePtr = CFArrayGetValueAtIndex ( findResults, backwards ? cnt : numOccurrences - cnt - 1 )
1476+ replaceCharacters ( in: NSRange ( rangePtr!. load ( as: CFRange . self) ) , with: replacement)
1477+ }
1478+
1479+ return numOccurrences
1480+ }
1481+
1482+ var newStorage = Substring ( )
1483+ var sourceStringCurrentIndex = _storage. startIndex
14691484 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)
1485+ let rangePtr = CFArrayGetValueAtIndex ( findResults, backwards ? numOccurrences - cnt - 1 : cnt)
1486+ let range = NSRange ( rangePtr!. load ( as: CFRange . self) )
1487+ let matchStartIndex = String . Index ( utf16Offset: range. location, in: _storage)
1488+ let matchEndIndex = String . Index ( utf16Offset: range. location + range. length, in: _storage)
1489+ newStorage += _storage [ sourceStringCurrentIndex..< matchStartIndex]
1490+ newStorage += replacement
1491+ sourceStringCurrentIndex = matchEndIndex
14721492 }
1493+ newStorage += _storage [ sourceStringCurrentIndex ..< _storage. endIndex]
1494+ _storage = String ( newStorage)
14731495 return numOccurrences
1474- } else {
1475- return 0
14761496 }
1477-
14781497 }
14791498
14801499 public func applyTransform( _ transform: String , reverse: Bool , range: NSRange , updatedRange resultingRange: NSRangePointer ? ) -> Bool {
0 commit comments