How do you use String.substringWithRange? (or, how

2019-01-01 06:00发布

I have not yet been able to figure out how to get a substring of a String in Swift:

var str = “Hello, playground”
func test(str: String) -> String {
 return str.substringWithRange( /* What goes here? */ )
}
test (str)

I'm not able to create a Range in Swift. Autocomplete in the Playground isn’t super helpful - this is what it suggests:

return str.substringWithRange(aRange: Range<String.Index>)

I haven't found anything in the Swift Standard Reference Library that helps. Here was another wild guess:

return str.substringWithRange(Range(0, 1))

And this:

let r:Range<String.Index> = Range<String.Index>(start: 0, end: 2)
return str.substringWithRange(r)

I've seen other answers (Finding index of character in Swift String) that seem to suggest that since String is a bridge type for NSString, the "old" methods should work, but it's not clear how - e.g., this doesn't work either (doesn't appear to be valid syntax):

let x = str.substringWithRange(NSMakeRange(0, 3))

Thoughts?

标签: swift
30条回答
倾城一夜雪
2楼-- · 2019-01-01 06:40

The short answer is that this is really hard in Swift right now. My hunch is that there is still a bunch of work for Apple to do on convenience methods for things like this.

String.substringWithRange() is expecting a Range<String.Index> parameter, and as far as I can tell there isn't a generator method for the String.Index type. You can get String.Index values back from aString.startIndex and aString.endIndex and call .succ() or .pred() on them, but that's madness.

How about an extension on the String class that takes good old Ints?

extension String {
    subscript (r: Range<Int>) -> String {
        get {
            let subStart = advance(self.startIndex, r.startIndex, self.endIndex)
            let subEnd = advance(subStart, r.endIndex - r.startIndex, self.endIndex)
            return self.substringWithRange(Range(start: subStart, end: subEnd))
        }
    }
    func substring(from: Int) -> String {
        let end = countElements(self)
        return self[from..<end]
    }
    func substring(from: Int, length: Int) -> String {
        let end = from + length
        return self[from..<end]
    }
}

let mobyDick = "Call me Ishmael."
println(mobyDick[8...14])             // Ishmael

let dogString = "This                                                                     
查看更多
步步皆殇っ
3楼-- · 2019-01-01 06:40

I tried to come up with something Pythonic.

All the subscripts here are great, but the times I really need something simple is usually when I want to count from back, e.g. string.endIndex.advancedBy(-1)

It supports nil values, for both start and end index, where nil would mean index at 0 for start, string.characters.count for end.

extension String {
    var subString: (Int?) -> (Int?) -> String {
        return { (start) in
            { (end) in
                let startIndex = start ?? 0 < 0 ? self.endIndex.advancedBy(start!) : self.startIndex.advancedBy(start ?? 0)
                let endIndex = end ?? self.characters.count < 0 ? self.endIndex.advancedBy(end!) : self.startIndex.advancedBy(end ?? self.characters.count)

                return startIndex > endIndex ? "" : self.substringWithRange(startIndex ..< endIndex)
            }
        }
    }
}

let dog = "Dog‼                                                                    
查看更多
栀子花@的思念
4楼-- · 2019-01-01 06:40
let startIndex = text.startIndex
var range = startIndex.advancedBy(1) ..< text.endIndex.advancedBy(-4)
let substring = text.substringWithRange(range)

Full sample you can see here

查看更多
查无此人
5楼-- · 2019-01-01 06:41

If you have an NSRange, bridging to NSString works seamlessly. For example, I was doing some work with UITextFieldDelegate and I quickly wanted to compute the new string value when it asked if it should replace the range.

func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
    let newString = (textField.text as NSString).stringByReplacingCharactersInRange(range, withString: string)
    println("Got new string: ", newString)
}
查看更多
牵手、夕阳
6楼-- · 2019-01-01 06:42

Since String is a bridge type for NSString, the "old" methods should work, but it's not clear how - e.g., this doesn't work either (doesn't appear to be valid syntax):

 let x = str.substringWithRange(NSMakeRange(0, 3))

To me, that is the really interesting part of your question. String is bridged to NSString, so most NSString methods do work directly on a String. You can use them freely and without thinking. So, for example, this works just as you expect:

// delete all spaces from Swift String stateName
stateName = stateName.stringByReplacingOccurrencesOfString(" ", withString:"")

But, as so often happens, "I got my mojo workin' but it just don't work on you." You just happened to pick one of the rare cases where a parallel identically named Swift method exists, and in a case like that, the Swift method overshadows the Objective-C method. Thus, when you say str.substringWithRange, Swift thinks you mean the Swift method rather than the NSString method — and then you are hosed, because the Swift method expects a Range<String.Index>, and you don't know how to make one of those.

The easy way out is to stop Swift from overshadowing like this, by casting explicitly:

let x = (str as NSString).substringWithRange(NSMakeRange(0, 3))

Note that no significant extra work is involved here. "Cast" does not mean "convert"; the String is effectively an NSString. We are just telling Swift how to look at this variable for purposes of this one line of code.

The really weird part of this whole thing is that the Swift method, which causes all this trouble, is undocumented. I have no idea where it is defined; it is not in the NSString header and it's not in the Swift header either.

查看更多
千与千寻千般痛.
7楼-- · 2019-01-01 06:42

here is a example to get video-Id only .i.e (6oL687G0Iso) from the whole URL in swift

let str = "https://www.youtube.com/watch?v=6oL687G0Iso&list=PLKmzL8Ib1gsT-5LN3V2h2H14wyBZTyvVL&index=2"
var arrSaprate = str.componentsSeparatedByString("v=")
let start = arrSaprate[1]
let rangeOfID = Range(start: start.startIndex,end:start.startIndex.advancedBy(11))
let substring = start[rangeOfID]
print(substring)
查看更多
登录 后发表回答