Swift: วิธีรับสตริงย่อยจากจุดเริ่มต้นจนถึงดัชนีสุดท้ายของอักขระ


110

ฉันต้องการเรียนรู้วิธีที่ดีที่สุด / ง่ายที่สุดในการเปลี่ยนสตริงให้เป็นสตริงอื่น แต่มีเพียงส่วนย่อยเริ่มต้นที่จุดเริ่มต้นและไปที่ดัชนีสุดท้ายของอักขระ

ตัวอย่างเช่นแปลง "www.stackoverflow.com" เป็น "www.stackoverflow" ข้อมูลโค้ดใดที่จะทำเช่นนั้นและเป็นข้อมูลที่รวดเร็วที่สุด (ฉันหวังว่านี่จะไม่ทำให้เกิดการถกเถียง แต่ฉันไม่พบบทเรียนที่ดีเกี่ยวกับวิธีจัดการสตริงย่อยใน Swift

คำตอบ:


202

เพียงแค่เข้าถึงย้อนหลัง

วิธีที่ดีที่สุดคือใช้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 สำนวนบริสุทธิ์

Swift 2.0

advanceตอนนี้เป็นส่วนหนึ่งของและถูกเรียกว่าIndex advancedByคุณชอบ:

var string1 = "www.stackoverflow.com"

var index1 = string1.endIndex.advancedBy(-4)

var substring1 = string1.substringToIndex(index1)

Swift 3.0

คุณไม่สามารถเรียกadvancedByใช้ a ได้Stringเนื่องจากมีองค์ประกอบขนาดตัวแปร คุณต้องใช้index(_, offsetBy:).

var string1 = "www.stackoverflow.com"

var index1 = string1.index(string1.endIndex, offsetBy: -4)

var substring1 = string1.substring(to: index1)

หลายสิ่งหลายอย่างถูกเปลี่ยนชื่อ กรณีที่จะถูกเขียนใน CamelCase, กลายเป็นstartIndexlowerBound

var string2 = "www.stackoverflow.com"

var index2 = string2.range(of: ".", options: .backwards)?.lowerBound

var substring2 = string2.substring(to: index2!)

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:))

1
ขอบคุณ @ fpg1503. นี่คือคำตอบที่ฉันต้องการหา คำตอบอื่น ๆ สอนฉันหรือทำให้ฉันนึกถึงคุณลักษณะต่างๆในภาษา แต่นี่คือวิธีที่ฉันจะใช้เพื่อแก้ปัญหาของฉัน
Jason Hocker

1
การใช้ Swift 2.0 string1.endIndex.advancedBy(-4)ทำงานแทนฉันadvance
Alex Koshy

92
ไม่มีวิธีง่ายๆในการทำสิ่งนี้อย่างจริงจังหรือ?
devios1

12
@devios จริงทั้งหมด. ฉันรู้สึกขอบคุณสำหรับ Swift เมื่อเทียบกับ Objective-C แต่ IMHO ความกังวลที่นำไปสู่รหัสที่น่าอึดอัดใจนี้ไม่เกี่ยวข้องกับ 99% ของรหัสและตัวเข้ารหัส แย่กว่านั้นเราจะเขียนส่วนขยายความสะดวกที่ไม่ดีเสียเอง หากนักพัฒนาทั่วไปไม่เข้าใจข้อกังวลระดับสูงเหล่านี้พวกเขาก็สามารถเขียน ad-hoc API เพื่อจัดการกับปัญหาคนเดินเท้าที่เราสร้างซอฟต์แวร์ได้อย่างน้อยที่สุด แนวโน้มที่จะเปลี่ยนไปNSStringเป็นสิ่งที่ไม่ดีอย่างเห็นได้ชัดเช่นกันเพราะในที่สุดเราทุกคนก็ต้องการหนีจากชั้นเรียนพื้นฐาน (มรดก) เลย .... พร่ำเพ้อ!
Dan Rosenstark

2
สวิฟท์ใน 4 string1[..<index1]ที่คุณสามารถทำได้ ไม่จำเป็นต้องstring1.startIndex.
bauerMusic

26

Swift 3, XCode 8

func lastIndexOfCharacter(_ c: Character) -> Int? {
    return range(of: String(c), options: .backwards)?.lowerBound.encodedOffset
}

นับตั้งแต่advancedBy(Int)มีการหายไปตั้งแต่สวิฟท์ 3 ใช้วิธีการString 's 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

PS มันจริงๆแปลกที่นักพัฒนาบังคับให้จัดการกับแทนธรรมดาString.Index Intทำไมเราต้องกังวลเกี่ยวกับStringกลไกภายในและไม่ใช่แค่มีsubstring()วิธีการง่ายๆ


คุณไม่ควรใช้encodedOffsetตรวจสอบความคิดเห็นนี้และวิธีที่ถูกต้องในการทำให้สำเร็จstackoverflow.com/questions/34540185/…
Leo Dabus

18

ฉันจะทำโดยใช้ตัวห้อย (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

11

แก้ไข / ปรับปรุง:

ในSwift 4 หรือใหม่กว่า (Xcode 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"
}

นี่เป็นคำตอบที่ดี แต่ดูเหมือนว่าด้วย Swift 2 คุณสมบัตินี้ได้ถูกย้ายไปที่ NSUrl แล้ว บางทีสิ่งนี้อาจช่วยให้ผู้คนอ่านสิ่งนี้ในอนาคต ...
chuky

8

นี่คือวิธีที่ฉันทำ คุณสามารถทำได้ในลักษณะเดียวกันหรือใช้รหัสนี้เพื่อเป็นแนวคิด

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)
  }

}

เครดิตalbertbori / Common Swift String Extensions

โดยทั่วไปฉันเป็นผู้เสนอส่วนขยายที่ชัดเจนโดยเฉพาะอย่างยิ่งสำหรับความต้องการเช่นการจัดการสตริงการค้นหาและการแบ่งส่วน


2
ฉันคิดว่านี่เป็นสิ่งที่ Apple ควรทำเพื่อปรับปรุง API ของ String ใน Swift
skyline75489

2
กำลังมองหา API นี้ Apple Swift ขาด API พื้นฐานจำนวนมาก เป็นภาษาที่ซับซ้อนมากและยังไม่สมบูรณ์ Swift เป็นเรื่องไร้สาระ!
Loc

นี่คือการแยกและอัปเดตเป็นเวอร์ชัน Swift 3 ของไลบรารีที่คุณอ้างอิง: github.com/iamjono/SwiftString
RenniePet

5

String มีคุณสมบัติสตริงย่อยในตัว:

extension String : Sliceable {
    subscript (subRange: Range<String.Index>) -> String { get }
}

หากสิ่งที่คุณต้องการคือ "ไปที่ดัชนีแรกของอักขระ" คุณสามารถรับสตริงย่อยโดยใช้find()ฟังก์ชันbuiltin :

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
}

ดูเหมือนว่าตัวห้อยสำหรับ String จะไม่มีใน Swift 2.0 คุณรู้หรือไม่ว่ามีการแทนที่หรือไม่
Cory

คุณรู้หรือไม่ว่าฉันจะ จำกัด Index เป็น BidirectionalIndexType ใน Swift 4 หรือใหม่กว่าได้อย่างไร
Leo Dabus

5

คุณสามารถใช้ส่วนขยายเหล่านี้:

Swift 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)

5

Swift 4:

extension String {

    /// the length of the string
    var length: Int {
        return self.characters.count
    }

    /// Get substring, e.g. "ABCDE".substring(index: 2, length: 3) -> "CDE"
    ///
    /// - parameter index:  the start index
    /// - parameter length: the length of the substring
    ///
    /// - returns: the substring
    public func substring(index: Int, length: Int) -> String {
        if self.length <= index {
            return ""
        }
        let leftIndex = self.index(self.startIndex, offsetBy: index)
        if self.length <= index + length {
            return self.substring(from: leftIndex)
        }
        let rightIndex = self.index(self.endIndex, offsetBy: -(self.length - index - length))
        return self.substring(with: leftIndex..<rightIndex)
    }

    /// Get substring, e.g. -> "ABCDE".substring(left: 0, right: 2) -> "ABC"
    ///
    /// - parameter left:  the start index
    /// - parameter right: the end index
    ///
    /// - returns: the substring
    public func substring(left: Int, right: Int) -> String {
        if length <= left {
            return ""
        }
        let leftIndex = self.index(self.startIndex, offsetBy: left)
        if length <= right {
            return self.substring(from: leftIndex)
        }
        else {
            let rightIndex = self.index(self.endIndex, offsetBy: -self.length + right + 1)
            return self.substring(with: leftIndex..<rightIndex)
        }
    }
}

คุณสามารถทดสอบได้ดังนี้:

    print("test: " + String("ABCDE".substring(index: 2, length: 3) == "CDE"))
    print("test: " + String("ABCDE".substring(index: 0, length: 3) == "ABC"))
    print("test: " + String("ABCDE".substring(index: 2, length: 1000) == "CDE"))
    print("test: " + String("ABCDE".substring(left: 0, right: 2) == "ABC"))
    print("test: " + String("ABCDE".substring(left: 1, right: 3) == "BCD"))
    print("test: " + String("ABCDE".substring(left: 3, right: 1000) == "DE"))

ตรวจสอบhttps://gitlab.com/seriyvolk83/SwiftExไลบรารี ประกอบด้วยวิธีการเหล่านี้และวิธีการอื่น ๆ ที่เป็นประโยชน์


4

คุณต้องการรับสตริงย่อยของสตริงจากดัชนีเริ่มต้นไปยังดัชนีสุดท้ายของอักขระตัวใดตัวหนึ่ง? ในกรณีนี้คุณสามารถเลือกหนึ่งในวิธีการ Swift 2.0+ ต่อไปนี้

วิธีการที่ต้องการ Foundation

รับสตริงย่อยที่มีดัชนีสุดท้ายของอักขระ:

import Foundation

let string = "www.stackoverflow.com"
if let rangeOfIndex = string.rangeOfCharacterFromSet(NSCharacterSet(charactersInString: "."), options: .BackwardsSearch) {
    print(string.substringToIndex(rangeOfIndex.endIndex))
}

// prints "www.stackoverflow."

รับสตริงย่อยที่ไม่รวมดัชนีสุดท้ายของอักขระ:

import Foundation

let string = "www.stackoverflow.com"
if let rangeOfIndex = string.rangeOfCharacterFromSet(NSCharacterSet(charactersInString: "."), options: .BackwardsSearch) {
    print(string.substringToIndex(rangeOfIndex.startIndex))
}

// prints "www.stackoverflow"

หากคุณต้องการทำซ้ำการดำเนินการเหล่านั้นการขยายStringอาจเป็นทางออกที่ดี:

import Foundation

extension String {
    func substringWithLastInstanceOf(character: Character) -> String? {
        if let rangeOfIndex = rangeOfCharacterFromSet(NSCharacterSet(charactersInString: String(character)), options: .BackwardsSearch) {
            return self.substringToIndex(rangeOfIndex.endIndex)
        }
        return nil
    }
    func substringWithoutLastInstanceOf(character: Character) -> String? {
        if let rangeOfIndex = rangeOfCharacterFromSet(NSCharacterSet(charactersInString: String(character)), options: .BackwardsSearch) {
            return self.substringToIndex(rangeOfIndex.startIndex)
        }
        return nil
    }
}

print("www.stackoverflow.com".substringWithLastInstanceOf("."))
print("www.stackoverflow.com".substringWithoutLastInstanceOf("."))

/*
prints:
Optional("www.stackoverflow.")
Optional("www.stackoverflow")
*/

วิธีการที่ไม่ต้องการ Foundation

รับสตริงย่อยที่มีดัชนีสุดท้ายของอักขระ:

let string = "www.stackoverflow.com"
if let reverseIndex = string.characters.reverse().indexOf(".") {
    print(string[string.startIndex ..< reverseIndex.base])
}

// prints "www.stackoverflow."

รับสตริงย่อยที่ไม่รวมดัชนีสุดท้ายของอักขระ:

let string = "www.stackoverflow.com"
if let reverseIndex = string.characters.reverse().indexOf(".") {
    print(string[string.startIndex ..< reverseIndex.base.advancedBy(-1)])
}

// prints "www.stackoverflow"

หากคุณต้องการทำซ้ำการดำเนินการเหล่านั้นการขยายStringอาจเป็นทางออกที่ดี:

extension String {
    func substringWithLastInstanceOf(character: Character) -> String? {
        if let reverseIndex = characters.reverse().indexOf(".") {
            return self[self.startIndex ..< reverseIndex.base]
        }
        return nil
    }
    func substringWithoutLastInstanceOf(character: Character) -> String? {
        if let reverseIndex = characters.reverse().indexOf(".") {
            return self[self.startIndex ..< reverseIndex.base.advancedBy(-1)]
        }
        return nil
    }
}

print("www.stackoverflow.com".substringWithLastInstanceOf("."))
print("www.stackoverflow.com".substringWithoutLastInstanceOf("."))

/*
prints:
Optional("www.stackoverflow.")
Optional("www.stackoverflow")
*/

4

นี่เป็นวิธีที่ง่ายและสั้นในการรับสตริงย่อยหากคุณทราบดัชนี:

let s = "www.stackoverflow.com"
let result = String(s.characters.prefix(17)) // "www.stackoverflow"

แอปจะไม่ขัดข้องหากดัชนีของคุณเกินความยาวของสตริง:

let s = "short"
let result = String(s.characters.prefix(17)) // "short"

ทั้งสองตัวอย่างคือSwift 3 พร้อมแล้ว


4

สิ่งหนึ่งที่เพิ่มเสียงดังคือการทำซ้ำstringVar:

stringVar [ stringVar .index ( stringVar .startIndex, offsetBy: ... )

ในSwift 4

ส่วนขยายสามารถลดบางส่วนได้:

extension String {

    func index(at: Int) -> String.Index {
        return self.index(self.startIndex, offsetBy: at)
    }
}

จากนั้นการใช้งาน:

let string = "abcde"

let to = string[..<string.index(at: 3)] // abc
let from = string[string.index(at: 3)...] // de

ควรสังเกตว่าtoและfromเป็นประเภทSubstring(หรือString.SubSequance) พวกเขาไม่จัดสรรสตริงใหม่และมีประสิทธิภาพมากขึ้นสำหรับการประมวลผล

ในการเรียกคืนStringประเภทSubstringจะต้องถูกส่งกลับไปที่String:

let backToString = String(from)

นี่คือที่ในที่สุดสตริงจะถูกจัดสรร


3
func substr(myString: String, start: Int, clen: Int)->String

{
  var index2 = string1.startIndex.advancedBy(start)
  var substring2 = string1.substringFromIndex(index2)
  var index1 = substring2.startIndex.advancedBy(clen)
  var substring1 = substring2.substringToIndex(index1)

  return substring1   
}

substr(string1, start: 3, clen: 5)

3

สวิฟต์ 3

let string = "www.stackoverflow.com"
let first3Characters = String(string.characters.prefix(3)) // www
let lastCharacters = string.characters.dropFirst(4) // stackoverflow.com (it would be a collection)

//or by index 
let indexOfFouthCharacter = olNumber.index(olNumber.startIndex, offsetBy: 4)
let first3Characters = olNumber.substring(to: indexOfFouthCharacter) // www
let lastCharacters = olNumber.substring(from: indexOfFouthCharacter) // .stackoverflow.com

บทความดีๆเพื่อความเข้าใจทำไมเราถึงต้องการสิ่งนี้


2

ฉันได้ขยาย String ด้วยสองวิธีการสตริงย่อย คุณสามารถเรียกสตริงย่อยด้วย from / to range หรือ from / length ได้ดังนี้:

var bcd = "abcdef".substring(1,to:3)
var cde = "abcdef".substring(2,to:-2)
var cde = "abcdef".substring(2,length:3)

extension String {
  public func substring(from:Int = 0, var to:Int = -1) -> String {
    if to < 0 {
        to = self.length + to
    }
    return self.substringWithRange(Range<String.Index>(
        start:self.startIndex.advancedBy(from),
        end:self.startIndex.advancedBy(to+1)))
  }
  public func substring(from:Int = 0, length:Int) -> String {
    return self.substringWithRange(Range<String.Index>(
        start:self.startIndex.advancedBy(from),
        end:self.startIndex.advancedBy(from+length)))
  }
}

self.length ไม่สามารถใช้งานได้อีกต่อไป คุณต้องเพิ่มสิ่งนี้ในส่วนขยาย (Andrewz โปรดอัปเดตโค้ดฉันไม่ต้องการโพสต์คำตอบอื่น): public func length () -> Int {return self.lengthOfBytesUsingEncoding (NSUTF16StringEncoding)}
philippe

1

Swift 2.0 โค้ดด้านล่างได้รับการทดสอบบน XCode 7.2 โปรดดูภาพหน้าจอที่แนบมาด้านล่าง

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        var mainText = "http://stackoverflow.com"

        var range = Range(start: mainText.startIndex.advancedBy(7), end: mainText.startIndex.advancedBy(24))
        var subText = mainText.substringWithRange(range)


        //OR Else use below for LAST INDEX

        range = Range(start: mainText.startIndex.advancedBy(7), end: mainText.endIndex)
        subText = mainText.substringWithRange(range)
    }
}

1

ใน Swift 5

เราต้องการString.Indexแทนค่า Int ธรรมดาเพื่อแสดงดัชนี

โปรดจำไว้ว่าเมื่อเราพยายามรับ subString จาก Swift String(ประเภทค่า) เราต้องวนซ้ำด้วยSequenceโปรโตคอลซึ่งจะส่งกลับString.SubSequenceประเภทแทนที่จะเป็นStringประเภท

หากต้องการกลับStringจากString.SubSequenceให้ใช้String(subString)

ตัวอย่างด้านล่าง:

    let string = "https://stackoverflow.com"
    let firstIndex = String.Index(utf16Offset: 0, in: string)
    let lastIndex = String.Index(utf16Offset: 6, in: string)
    let subString = String(string[firstIndex...lastIndex])

0

สำหรับSwift 2.0จะเป็นเช่นนี้:

var string1 = "www.stackoverflow.com"
var index1 = string1.endIndex.advancedBy(-4)
var substring1 = string1.substringToIndex(index1)

บางทีพวกเขาอาจจะเปลี่ยนไป แต่มันเป็น 'advancedBy' (สังเกต 'd' ที่ท้าย 'advanced')
Wedge Martin

0

ฉันได้แก้ไขโพสต์ของ andrewz เพื่อให้เข้ากันได้กับ Swift 2.0 (และอาจจะเป็น Swift 3.0) ในความเห็นที่ต่ำต้อยของฉันส่วนขยายนี้เข้าใจง่ายกว่าและคล้ายกับที่มีอยู่ในภาษาอื่น ๆ (เช่น PHP)

extension String {

    func length() -> Int {
        return self.lengthOfBytesUsingEncoding(NSUTF16StringEncoding)
    }
    func substring(from:Int = 0, to:Int = -1) -> String {
       var nto=to
        if nto < 0 {
            nto = self.length() + nto
        }
        return self.substringWithRange(Range<String.Index>(
           start:self.startIndex.advancedBy(from),
           end:self.startIndex.advancedBy(nto+1)))
    }
    func substring(from:Int = 0, length:Int) -> String {
        return self.substringWithRange(Range<String.Index>(
            start:self.startIndex.advancedBy(from),
            end:self.startIndex.advancedBy(from+length)))
    }
}

0

ฉันยังสร้างส่วนขยาย String แบบง่ายสำหรับ Swift 4:

extension String {
    func subStr(s: Int, l: Int) -> String { //s=start, l=lenth
        let r = Range(NSRange(location: s, length: l))!
        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])
     }
}

เรียกง่ายๆว่าแบบนี้

"Hallo world".subStr(s: 1, l: 3) //prints --> "all"

0

ลองใช้Int-basedวิธีแก้ปัญหานี้:

extension String {
    // start and end is included
    func intBasedSubstring(_ start: Int, _ end: Int) -> String {
        let endOffset: Int = -(count - end - 1)
        let startIdx = self.index(startIndex, offsetBy: start)
        let endIdx = self.index(endIndex, offsetBy: endOffset)
        return String(self[startIdx..<endIdx])
    }
}

หมายเหตุ: เป็นเพียงการฝึกฝน มันไม่ได้ตรวจสอบขอบเขต ปรับเปลี่ยนให้เหมาะกับความต้องการของคุณ


-1

นี่คือวิธีง่ายๆในการรับสตริงย่อยใน Swift

import UIKit

var str = "Hello, playground" 
var res = NSString(string: str)
print(res.substring(from: 4))
print(res.substring(to: 10))

OP ถามว่า "วิธีรับสตริงย่อยจากจุดเริ่มต้นถึงดัชนีสุดท้ายของอักขระ" ไม่ใช่วิธีรับสตริงย่อยโดยใช้ค่าฮาร์ดโค้ดที่กำหนดไว้ล่วงหน้า
Eric Aya

นี่คือตัวอย่างดั้งเดิม: แปลง "www.stackoverflow.com" เป็น "www.stackoverflow" หากคุณต้องการสตริงย่อยจากจุดเริ่มต้นไปยังจุดสิ้นสุดก็ไม่มีอะไรต้องทำเช่นผลลัพธ์คือสตริงอินพุตตามที่เป็นอยู่ โปรดเรียกคืนประโยชน์ของคำตอบข้างต้น
ZagorTeNej
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.