Resolved How to properly use rangeOfString on Swift?

Discussion in 'Mac Programming' started by raison, Jan 14, 2016.

  1. raison macrumors member

    Joined:
    Nov 13, 2009
    #1
    I'm trying to grab everything after # on a string, so for this string:

    A B C #123 456

    I want to get 123 456.

    I have "line" defined as String, and then I issue this:

    Code:
    let cmtRange: Range = line.rangeOfString("#")!
    What should I do next? I can't understand the documentation very well, quite confusing. It has that rangeOfString returns NSRange, but in reality, it returns Range.

    This doesn't work:
    Code:
    if(cmtRange.startIndex != NSNotFound) { ... } 
    This is the documentation I'm looking at, am I looking at the wrong place?
     
  2. xStep macrumors 68000

    Joined:
    Jan 28, 2003
    Location:
    Less lost in L.A.
    #2
    I played with this a little. I had to remove the exclamation mark to work with the result due to the possibility that the string does not contain the # character. Also, I believe that for Swift Apple has removed the use of NSNotFound.

    Anyhow, I've demonstrated two ways to work the return value. The first by using the 'if let' syntax and the second using your method of first assigning to a variable for further use.

    Code:
    var line = "ABC # 123 456"
    
    
    if let cmtRange1 = line.rangeOfString("#") {
        print("cmtRange1: \(cmtRange1)")
    }
    else {
        print("cmtRange1 is nil")
    }
    
    
    let cmtRange2 = line.rangeOfString("#")
    if cmtRange2 != nil {
        print("cmtRange2: \(cmtRange2)")
    }
    else {
        print("cmtRange2 is nil")
    }
    
    if cmtRange2 != nil {
        let remainderStr = line.substringFromIndex(cmtRange2!.endIndex)
        let trimmedStr = remainderStr.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet())
        print("right Str: >\(remainderStr)<")
        print("trmd Str: >\(trimmedStr)<")
    }
    
     
  3. gnasher729, Jan 15, 2016
    Last edited by a moderator: Jan 15, 2016

    gnasher729 macrumors P6

    gnasher729

    Joined:
    Nov 25, 2005
    #3
    Swift is not stable yet.

    One of the recent changes was removing the "NS" from various types - NS stands for NextStep, and if you know what NextStep is, then you are not a software developer but a software historian.

    In Objective-C, the method _always_ returns an NSRange, and if the string isn't found, then startIndex == NSNotFound. In Swift, the same method returns an optional range - either nil, or a valid range. The ! means: "Please crash if the string isn't found". So in Swift you don't compare with NSNotFound; it will never be equal to NSNotFound, but


    Code:
    if let range = line.rangeOfString ("#") {
            // range is the range where the # was found
        } else {
            // rangeOfString returned nil.
            // There is no # in the string
        }
     
  4. raison, Jan 15, 2016
    Last edited: Jan 15, 2016

    raison thread starter macrumors member

    Joined:
    Nov 13, 2009
    #4
    Thank you so much for both of you. @xStep I will try your code soon, thanks for your time for putting it together! I see that you defined 2 ranges, cmtRange1 and cmtRange2. I assume this was for demonstration purpose, right? I can use cmtRange1 to retrieve what I want, it seems like. Anyway, I'll give it a try in a bit and let you know, thanks a lot!

    @gnasher729 Thank you for the info. I'm relying on the XCode and developer.apple.com documentation sets, is there an updated documentation somewhere? I understand what you said, but I can't find in the documentation what you mentioned, such as returning Range instead of NSRange, and returning nil instead of NSNotFound. Did you get that from your experience with coding on Swift, or is it documented somewhere?

    EDIT: I tested and worked like a charm, thanks @xStep. I also reread your comments and understood the reason for the 2 versions.
     
  5. xStep macrumors 68000

    Joined:
    Jan 28, 2003
    Location:
    Less lost in L.A.
    #5
    It looks like the duality of NSString and String adds to the confusion.

    Code:
    let abc : NSString = "Objective-C"
    let xyz = abc.rangeOfString("-") // <- This returns an NSRange because abc is a NSString
    if xyz.location == NSNotFound { // <- Now we can test against NSNotFound
        print("xyz.location is NSNotFound")
    }
    else {
        print("xyz: \(xyz)")
    }
    [SIZE=13px][\CODE][/SIZE]
     
  6. Madd the Sane macrumors 6502

    Madd the Sane

    Joined:
    Nov 8, 2010
    Location:
    Utah
    #6
    NSRange and NSNotFound are not dead: they're just not recommended. If you really need NSRange for whatever reason, you can cast String to NSString:
    Code:
    var aRange = ("Hi" as NSString).rangeOfString("H") //returns an NSRange
    
    This isn't reccommended, as converting to NSStrings take some time, and it'll begin adding up.

    That said, there are times you'll need to use NSString's range, as String and NSString count characters differently, and some Objective-C/Cocoa functions expect NSRanges
     

Share This Page