[ios] Swift : 문자의 처음부터 마지막 인덱스까지 부분 문자열을 얻는 방법
문자열을 다른 문자열로 바꾸는 가장 좋은 / 간단한 방법을 배우고 싶지만 하위 집합 만 사용하여 문자의 시작 부분에서 시작하여 마지막 인덱스로 이동합니다.
예를 들어 “www.stackoverflow.com”을 “www.stackoverflow”로 변환합니다. 어떤 코드 스 니펫이이를 수행하고 가장 신속하게 처리 할 수 있습니까? (나는 이것이 논쟁을 불러 일으키지 않기를 바라지 만, Swift에서 부분 문자열을 처리하는 방법에 대한 좋은 교훈을 찾을 수 없습니다.
답변
뒤로 접근
가장 좋은 방법은 속성과 전역 함수를 substringToIndex결합 하여 사용 endIndex하는 advance것입니다.
var string1 = "www.stackoverflow.com"
var index1 = advance(string1.endIndex, -4)
var substring1 = string1.substringToIndex(index1)
뒤에서 시작하는 문자열을 찾고
사용 rangeOfString및 설정 options에.BackwardsSearch
var string2 = "www.stackoverflow.com"
var index2 = string2.rangeOfString(".", options: .BackwardsSearch)?.startIndex
var substring2 = string2.substringToIndex(index2!)
확장 없음, 순수한 관용적 Swift
스위프트 2.0
advance이제의 일부 Index이며이라고 advancedBy합니다. 다음과 같이합니다.
var string1 = "www.stackoverflow.com"
var index1 = string1.endIndex.advancedBy(-4)
var substring1 = string1.substringToIndex(index1)
스위프트 3.0
당신은 호출 할 수 없습니다 advancedByA의 String는 가변 크기의 요소를 가지고 있기 때문이다. 을 사용해야 index(_, offsetBy:)합니다.
var string1 = "www.stackoverflow.com"
var index1 = string1.index(string1.endIndex, offsetBy: -4)
var substring1 = string1.substring(to: index1)
많은 것들이 이름이 바뀌 었습니다. 사건은 낙타 표기법으로 작성되어, startIndex되었다 lowerBound.
var string2 = "www.stackoverflow.com"
var index2 = string2.range(of: ".", options: .backwards)?.lowerBound
var substring2 = string2.substring(to: index2!)
또한 force unwrapping을 권장하지 않습니다 index2. 선택적 바인딩 또는 map. 개인적으로 다음을 선호합니다 map.
var substring3 = index2.map(string2.substring(to:))
스위프트 4
Swift 3 버전은 여전히 유효하지만 이제 인덱스 범위와 함께 아래 첨자를 사용할 수 있습니다.
let string1 = "www.stackoverflow.com"
let index1 = string1.index(string1.endIndex, offsetBy: -4)
let substring1 = string1[..<index1]
두 번째 접근 방식은 변경되지 않습니다.
let string2 = "www.stackoverflow.com"
let index2 = string2.range(of: ".", options: .backwards)?.lowerBound
let substring3 = index2.map(string2.substring(to:))
답변
스위프트 3, XCode 8
func lastIndexOfCharacter(_ c: Character) -> Int? {
    return range(of: String(c), options: .backwards)?.lowerBound.encodedOffset
}
advancedBy(Int)Swift 3은 String‘s method를 사용 하기 때문에 사라졌습니다 index(String.Index, Int). String하위 문자열 및 친구들과 함께이 확장을 확인하십시오 .
public extension String {
    //right is the first encountered string after left
    func between(_ left: String, _ right: String) -> String? {
        guard let leftRange = range(of: left), let rightRange = range(of: right, options: .backwards)
        , leftRange.upperBound <= rightRange.lowerBound
            else { return nil }
        let sub = self.substring(from: leftRange.upperBound)
        let closestToLeftRange = sub.range(of: right)!
        return sub.substring(to: closestToLeftRange.lowerBound)
    }
    var length: Int {
        get {
            return self.characters.count
        }
    }
    func substring(to : Int) -> String {
        let toIndex = self.index(self.startIndex, offsetBy: to)
        return self.substring(to: toIndex)
    }
    func substring(from : Int) -> String {
        let fromIndex = self.index(self.startIndex, offsetBy: from)
        return self.substring(from: fromIndex)
    }
    func substring(_ r: Range<Int>) -> String {
        let fromIndex = self.index(self.startIndex, offsetBy: r.lowerBound)
        let toIndex = self.index(self.startIndex, offsetBy: r.upperBound)
        return self.substring(with: Range<String.Index>(uncheckedBounds: (lower: fromIndex, upper: toIndex)))
    }
    func character(_ at: Int) -> Character {
        return self[self.index(self.startIndex, offsetBy: at)]
    }
    func lastIndexOfCharacter(_ c: Character) -> Int? {
        guard let index = range(of: String(c), options: .backwards)?.lowerBound else
        { return nil }
        return distance(from: startIndex, to: index)
    }
}
Swift 4의 업데이트 된 확장
public extension String {
    //right is the first encountered string after left
    func between(_ left: String, _ right: String) -> String? {
        guard
            let leftRange = range(of: left), let rightRange = range(of: right, options: .backwards)
            , leftRange.upperBound <= rightRange.lowerBound
            else { return nil }
        let sub = self[leftRange.upperBound...]
        let closestToLeftRange = sub.range(of: right)!            
        return String(sub[..<closestToLeftRange.lowerBound])
    }
    var length: Int {
        get {
            return self.count
        }
    }
    func substring(to : Int) -> String {
        let toIndex = self.index(self.startIndex, offsetBy: to)
        return String(self[...toIndex])
    }
    func substring(from : Int) -> String {
        let fromIndex = self.index(self.startIndex, offsetBy: from)
        return String(self[fromIndex...])
    }
    func substring(_ r: Range<Int>) -> String {
        let fromIndex = self.index(self.startIndex, offsetBy: r.lowerBound)
        let toIndex = self.index(self.startIndex, offsetBy: r.upperBound)
        let indexRange = Range<String.Index>(uncheckedBounds: (lower: fromIndex, upper: toIndex))
        return String(self[indexRange])
    }
    func character(_ at: Int) -> Character {
        return self[self.index(self.startIndex, offsetBy: at)]
    }
    func lastIndexOfCharacter(_ c: Character) -> Int? {
        guard let index = range(of: String(c), options: .backwards)?.lowerBound else
        { return nil }
        return distance(from: startIndex, to: index)
    }
}
용법:
let text = "www.stackoverflow.com"
let at = text.character(3) // .
let range = text.substring(0..<3) // www
let from = text.substring(from: 4) // stackoverflow.com
let to = text.substring(to: 16) // www.stackoverflow
let between = text.between(".", ".") // stackoverflow
let substringToLastIndexOfChar = text.lastIndexOfCharacter(".") // 17
추신 : 개발자 String.Index가 평범한 대신 처리하도록 강요 한 것은 정말 이상합니다 Int. String단순한 substring()방법 이 아닌 내부 역학에 신경을 써야하는 이유는 무엇 입니까?
답변
아래 첨자 ( s[start..<end])를 사용하여 수행합니다 .
스위프트 3, 4, 5
let s = "www.stackoverflow.com"
let start = s.startIndex
let end = s.index(s.endIndex, offsetBy: -4)
let substring = s[start..<end] // www.stackoverflow
답변
편집 / 업데이트 :
년 이후 스위프트 4 (엑스 코드 10.0+) 새 사용할 수 있습니다 BidirectionalCollection의
 방법 으로 (는 lastIndex를 🙂 
func lastIndex(of element: Element) -> Int?
let string = "www.stackoverflow.com"
if let lastIndex = string.lastIndex(of: ".") {
    let subString = string[..<lastIndex]  // "www.stackoverflow"
}
답변
방법은 다음과 같습니다. 같은 방식으로 할 수도 있고 아이디어를 위해이 코드를 사용할 수도 있습니다.
let s = "www.stackoverflow.com"
s.substringWithRange(0..<s.lastIndexOf("."))
내가 사용하는 확장 프로그램은 다음과 같습니다.
import Foundation
extension String {
  var length: Int {
    get {
      return countElements(self)
    }
  }
  func indexOf(target: String) -> Int {
    var range = self.rangeOfString(target)
    if let range = range {
      return distance(self.startIndex, range.startIndex)
    } else {
      return -1
    }
  }
  func indexOf(target: String, startIndex: Int) -> Int {
    var startRange = advance(self.startIndex, startIndex)        
    var range = self.rangeOfString(target, options: NSStringCompareOptions.LiteralSearch, range: Range<String.Index>(start: startRange, end: self.endIndex))
    if let range = range {
      return distance(self.startIndex, range.startIndex)
    } else {
      return -1
    }
  }
  func lastIndexOf(target: String) -> Int {
    var index = -1
    var stepIndex = self.indexOf(target)
    while stepIndex > -1 {
      index = stepIndex
      if stepIndex + target.length < self.length {
        stepIndex = indexOf(target, startIndex: stepIndex + target.length)
      } else {
        stepIndex = -1
      }
    }
    return index
  } 
  func substringWithRange(range:Range<Int>) -> String {
    let start = advance(self.startIndex, range.startIndex)
    let end = advance(self.startIndex, range.endIndex)
    return self.substringWithRange(start..<end)
  }
}
Credit albertbori / Common Swift String Extensions
일반적으로 저는 특히 문자열 조작, 검색 및 슬라이싱과 같은 요구 사항에 대해 확장을 강력하게지지합니다.
답변
String 내장 하위 문자열 기능이 있습니다.
extension String : Sliceable {
    subscript (subRange: Range<String.Index>) -> String { get }
}
원하는 것이 ” 문자 의 첫 번째 인덱스로 이동”하는 것이라면 내장 find()함수를 사용하여 하위 문자열을 얻을 수 있습니다 .
var str = "www.stackexchange.com"
str[str.startIndex ..< find(str, ".")!] // -> "www"
마지막 인덱스 를 찾으려면 findLast().
/// Returns the last index where `value` appears in `domain` or `nil` if
/// `value` is not found.
///
/// Complexity: O(\ `countElements(domain)`\ )
func findLast<C: CollectionType where C.Generator.Element: Equatable>(domain: C, value: C.Generator.Element) -> C.Index? {
    var last:C.Index? = nil
    for i in domain.startIndex..<domain.endIndex {
        if domain[i] == value {
            last = i
        }
    }
    return last
}
let str = "www.stackexchange.com"
let substring = map(findLast(str, ".")) { str[str.startIndex ..< $0] } // as String?
// if "." is found, substring has some, otherwise `nil`
추가됨 :
아마도의 BidirectionalIndexType특수 버전 findLast이 더 빠를 것입니다.
func findLast<C: CollectionType where C.Generator.Element: Equatable, C.Index: BidirectionalIndexType>(domain: C, value: C.Generator.Element) -> C.Index? {
    for i in lazy(domain.startIndex ..< domain.endIndex).reverse() {
        if domain[i] == value {
            return i
        }
    }
    return nil
}
답변
다음 확장을 사용할 수 있습니다.
스위프트 2.3
 extension String
    {
        func substringFromIndex(index: Int) -> String
        {
            if (index < 0 || index > self.characters.count)
            {
                print("index \(index) out of bounds")
                return ""
            }
            return self.substringFromIndex(self.startIndex.advancedBy(index))
        }
        func substringToIndex(index: Int) -> String
        {
            if (index < 0 || index > self.characters.count)
            {
                print("index \(index) out of bounds")
                return ""
            }
            return self.substringToIndex(self.startIndex.advancedBy(index))
        }
        func substringWithRange(start: Int, end: Int) -> String
        {
            if (start < 0 || start > self.characters.count)
            {
                print("start index \(start) out of bounds")
                return ""
            }
            else if end < 0 || end > self.characters.count
            {
                print("end index \(end) out of bounds")
                return ""
            }
            let range = Range(start: self.startIndex.advancedBy(start), end: self.startIndex.advancedBy(end))
            return self.substringWithRange(range)
        }
        func substringWithRange(start: Int, location: Int) -> String
        {
            if (start < 0 || start > self.characters.count)
            {
                print("start index \(start) out of bounds")
                return ""
            }
            else if location < 0 || start + location > self.characters.count
            {
                print("end index \(start + location) out of bounds")
                return ""
            }
            let range = Range(start: self.startIndex.advancedBy(start), end: self.startIndex.advancedBy(start + location))
            return self.substringWithRange(range)
        }
    }
스위프트 3
extension String
{
    func substring(from index: Int) -> String
    {
        if (index < 0 || index > self.characters.count)
        {
            print("index \(index) out of bounds")
            return ""
        }
        return self.substring(from: self.characters.index(self.startIndex, offsetBy: index))
    }
    func substring(to index: Int) -> String
    {
        if (index < 0 || index > self.characters.count)
        {
            print("index \(index) out of bounds")
            return ""
        }
        return self.substring(to: self.characters.index(self.startIndex, offsetBy: index))
    }
    func substring(start: Int, end: Int) -> String
    {
        if (start < 0 || start > self.characters.count)
        {
            print("start index \(start) out of bounds")
            return ""
        }
        else if end < 0 || end > self.characters.count
        {
            print("end index \(end) out of bounds")
            return ""
        }
        let startIndex = self.characters.index(self.startIndex, offsetBy: start)
        let endIndex = self.characters.index(self.startIndex, offsetBy: end)
        let range = startIndex..<endIndex
        return self.substring(with: range)
    }
    func substring(start: Int, location: Int) -> String
    {
        if (start < 0 || start > self.characters.count)
        {
            print("start index \(start) out of bounds")
            return ""
        }
        else if location < 0 || start + location > self.characters.count
        {
            print("end index \(start + location) out of bounds")
            return ""
        }
        let startIndex = self.characters.index(self.startIndex, offsetBy: start)
        let endIndex = self.characters.index(self.startIndex, offsetBy: start + location)
        let range = startIndex..<endIndex
        return self.substring(with: range)
    }
}
용법:
let string = "www.stackoverflow.com"
let substring = string.substringToIndex(string.characters.count-4)
