iosstringswift2nsscanner

Replace numeric of different length in a string with different text length


Problem: Numeric is of different length could be 1, 200, 1000, 39 99995 etc. And need to replace with a text eg. "Apple" which is of different lenth comapring to the numeric values.

let str: String = "hello i have 1313 object of 10 string class with 1 object, similar to 9999 errors"

Expected Result = "hello i have Apple object of Apple string class with Apple object, similar to Apple errors"

I have tried with below code:

 var originalString: String = "hello i have 1313 object of 10 string class with 1 object, similar to 9999 errors"

    let strippedString: NSMutableString = NSMutableString(capacity: originalString.characters.count)
    var numArray: [String] = []
    var locArray: [NSNumber] = []
    var scanner: NSScanner = NSScanner(string:originalString)
    let numbers: NSCharacterSet = NSCharacterSet(charactersInString: "0123456789")
    while scanner.atEnd == false {
        var buffer: NSString?
        if scanner.scanCharactersFromSet(numbers, intoString: &buffer) {
            strippedString.appendString(buffer! as String)
            numArray.append(buffer! as String)
            locArray.append(scanner.scanLocation)
        }
        else {

            scanner.scanLocation = (scanner.scanLocation + 1)
        }
    }
    for (index, _) in numArray.enumerate() {
        var loc : Int = Int(locArray[index] ) - (String(numArray[index]).characters.count)
        let len = String(numArray[index]).characters.count
        let dupStr = "Apple"
        if(index != 0 && len !=  dupStr.characters.count)
        {
            loc = loc + (dupStr.characters.count - len) + 1
        }
        originalString.replaceRange(originalString.startIndex.advancedBy(loc)..<originalString.startIndex.advancedBy(loc + len), with: dupStr)
    }
    print(originalString)

Solution

  • Swift 2

    NSScanner is great, but if you want a simpler solution for this task, you could use componentsSeparatedByString, map, Int() and joinWithSeparator, like this:

    let originalString = "hello i have 1313 object of 10 string class with 1 object, similar to 9999 errors"
    let tokens = originalString.componentsSeparatedByString(" ")
    let newTokens = tokens.map { (token) -> String in
        if let _ = Int(token) {
            return "Apple"
        }
        return token
    }
    let result = newTokens.joinWithSeparator(" ")
    print(result)
    

    Prints:

    hello i have Apple object of Apple string class with Apple object, similar to Apple errors

    There's also a short version for the mapping:

    let newTokens = tokens.map { Int($0) != nil ? "Apple" : $0 }
    

    Swift 3

    componentsSeparatedByString(_:) is now components(separatedBy:), and joinWithSeparator(_:) is now joined(separator:).

    let tokens = originalString.components(separatedBy: " ")
    let newTokens = tokens.map { Int($0) != nil ? "Apple" : $0 }
    let result = newTokens.joined(separator: " ")