Swift: Cách lấy chuỗi con từ đầu đến chỉ mục cuối cùng của ký tự


110

Tôi muốn học cách tốt nhất / đơn giản nhất để biến một chuỗi thành một chuỗi khác nhưng chỉ với một tập hợp con, bắt đầu từ đầu và đi đến chỉ mục cuối cùng của một ký tự.

Ví dụ: chuyển đổi "www.stackoverflow.com" thành "www.stackoverflow". Đoạn mã nào sẽ làm điều đó và giống đoạn mã nhanh nhất? (Tôi hy vọng điều này không mang lại cuộc tranh luận, nhưng tôi không thể tìm thấy bài học hay về cách xử lý chuỗi con trong Swift.

Câu trả lời:


202

Chỉ truy cập ngược

Cách tốt nhất là sử dụng substringToIndexkết hợp thuộc endIndextính và advancechức năng toàn cục.

var string1 = "www.stackoverflow.com"

var index1 = advance(string1.endIndex, -4)

var substring1 = string1.substringToIndex(index1)

Tìm kiếm một chuỗi bắt đầu từ phía sau

Sử dụng rangeOfStringvà đặt optionsthành.BackwardsSearch

var string2 = "www.stackoverflow.com"

var index2 = string2.rangeOfString(".", options: .BackwardsSearch)?.startIndex

var substring2 = string2.substringToIndex(index2!)

Không có phần mở rộng, Swift thuần túy thành ngữ

Swift 2.0

advancebây giờ là một phần của Indexvà được gọi advancedBy. Bạn làm điều đó như:

var string1 = "www.stackoverflow.com"

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

var substring1 = string1.substringToIndex(index1)

Swift 3.0

Bạn không thể gọi advancedBya Stringvì nó có các phần tử kích thước thay đổi. Bạn phải sử dụng index(_, offsetBy:).

var string1 = "www.stackoverflow.com"

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

var substring1 = string1.substring(to: index1)

Rất nhiều thứ đã được đổi tên. Các trường hợp được viết bằng camelCase, startIndexđã trở thành lowerBound.

var string2 = "www.stackoverflow.com"

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

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

Ngoài ra, tôi không khuyên bạn nên bắt buộc mở gói index2. Bạn có thể sử dụng ràng buộc tùy chọn hoặc map. Cá nhân tôi thích sử dụng map:

var substring3 = index2.map(string2.substring(to:))

Swift 4

Phiên bản Swift 3 vẫn còn hiệu lực nhưng bây giờ bạn có thể sử dụng subscript với các phạm vi chỉ mục:

let string1 = "www.stackoverflow.com"

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

let substring1 = string1[..<index1]

Cách tiếp cận thứ hai vẫn không thay đổi:

let string2 = "www.stackoverflow.com"

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

let substring3 = index2.map(string2.substring(to:))

1
Cảm ơn @ fpg1503. Đây là loại câu trả lời mà tôi đang tìm kiếm. Các câu trả lời khác đã dạy tôi hoặc nhắc nhở tôi về các tính năng trong ngôn ngữ, nhưng đây là cách tôi sẽ sử dụng để giải quyết vấn đề của mình.
Jason Hocker

1
Sử dụng Swift 2.0, string1.endIndex.advancedBy(-4)đang làm việc cho tôi thay vìadvance
Alex Koshy.

92
Nghiêm túc không có cách nào để làm điều này một cách đơn giản?
defos1

12
@devios tất cả đều đúng. Tôi biết ơn Swift so với Objective-C, nhưng IMHO lo ngại dẫn đến đoạn mã cực kỳ khó xử này không liên quan đến 99% mã và lập trình viên ngoài kia. Tệ hơn nữa, chúng ta sẽ tự mình viết ra những tiện ích mở rộng tiện lợi không tốt. Nếu các nhà phát triển thông thường không thể hiểu những mối quan tâm cấp cao hơn này, họ là người ÍT NHẤT có thể viết một API đặc biệt để giải quyết những mối quan tâm của người đi bộ mà chúng tôi tạo ra phần mềm. Xu hướng chuyển đổi sang NSStringrõ ràng là không tốt, bởi vì cuối cùng tất cả chúng ta đều muốn thoát khỏi các lớp Nền tảng (kế thừa). Vì vậy, .... nhiều hơn nữa!
Dan Rosenstark

2
Trong Swift 4, bạn có thể làm được string1[..<index1]. Không cần string1.startIndex.
bauerMusic

26

Swift 3, XCode 8

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

Kể từ khi phương thức advancedBy(Int)sử dụng Swift 3 đã biến mất . Kiểm tra tiện ích mở rộng này với chuỗi con và bạn bè:Stringindex(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)
    }
}

Tiện ích mở rộng CẬP NHẬT cho 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)
    }
}

Sử dụng:

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 Thật kỳ lạ khi các nhà phát triển buộc phải xử lý String.Indexthay vì đơn giản Int. Tại sao chúng ta phải bận tâm về Stringcơ học bên trong mà không chỉ có các substring()phương pháp đơn giản ?


Bạn không nên sử dụng encodedOffsetkiểm tra nhận xét này và cách chính xác để thực hiện điều đó stackoverflow.com/questions/34540185/…
Leo Dabus

18

Tôi sẽ làm điều đó bằng cách sử dụng subscript ( s[start..<end]):

Swift 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

chỉnh sửa / cập nhật:

Trong Swift 4 trở lên (Xcode 10.0+), bạn có thể sử dụng phương thức BidirectionalCollection mới lastIndex (of :)

func lastIndex(of element: Element) -> Int?

let string = "www.stackoverflow.com"
if let lastIndex = string.lastIndex(of: ".") {
    let subString = string[..<lastIndex]  // "www.stackoverflow"
}

Đây là một câu trả lời tuyệt vời, nhưng có vẻ như với Swift 2, thuộc tính này đã được chuyển đến NSUrl. Có thể điều này sẽ giúp mọi người đọc điều này trong tương lai ...
chuky 16/02/16

8

Đây là cách tôi làm điều đó. Bạn có thể làm theo cách tương tự hoặc sử dụng mã này cho các ý tưởng.

let s = "www.stackoverflow.com"
s.substringWithRange(0..<s.lastIndexOf("."))

Đây là các tiện ích mở rộng tôi sử dụng:

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 / Tiện ích mở rộng chuỗi Swift chung

Nói chung, tôi là người ủng hộ mạnh mẽ các tiện ích mở rộng, đặc biệt cho các nhu cầu như thao tác chuỗi, tìm kiếm và cắt.


2
Tôi nghĩ đây thực sự là điều mà Apple nên làm, để cải thiện API của chuỗi trong Swift.
skyline75489

2
Tìm kiếm API này. Apple Swift đang thiếu rất nhiều API cơ bản. Nó là một ngôn ngữ rất phức tạp và cũng không hoàn chỉnh. Swift thật nhảm nhí!
Loc

Đây là phiên bản thư viện được chia nhỏ và cập nhật lên phiên bản Swift 3 mà bạn tham khảo: github.com/iamjono/SwiftString
RenniePet 14/12/16

5

String có tính năng chuỗi con nội trang:

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

Nếu những gì bạn muốn là "chuyển đến chỉ mục đầu tiên của một ký tự", bạn có thể lấy chuỗi con bằng cách sử dụng find()hàm nội trang :

var str = "www.stackexchange.com"
str[str.startIndex ..< find(str, ".")!] // -> "www"

Để tìm chỉ mục cuối cùng , chúng tôi có thể triển khai 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`

THÊM:

Có thể, BidirectionalIndexTypephiên bản chuyên biệt của findLastnhanh hơn:

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
}

Chỉ số phụ cho Chuỗi dường như không có trong Swift 2.0, bạn có biết cách thay thế không?
Cory

Bạn có biết làm cách nào để tôi có thể ràng buộc Index thành BidirectionalIndexType trong Swift 4 trở lên không?
Leo Dabus

5

Bạn có thể sử dụng các tiện ích mở rộng này:

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

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

Sử dụng:

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

bạn có thể kiểm tra nó như sau:

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

Kiểm tra thư viện https://gitlab.com/seriyvolk83/SwiftEx . Nó chứa những điều này và các phương pháp hữu ích khác.


4

Bạn có muốn nhận một chuỗi con của một chuỗi từ chỉ mục bắt đầu đến chỉ mục cuối cùng của một trong các ký tự của nó không? Nếu vậy, bạn có thể chọn một trong các phương pháp Swift 2.0+ sau.

Các phương pháp yêu cầu Foundation

Nhận một chuỗi con bao gồm chỉ mục cuối cùng của một ký tự:

import Foundation

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

// prints "www.stackoverflow."

Nhận một chuỗi con KHÔNG bao gồm chỉ mục cuối cùng của một ký tự:

import Foundation

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

// prints "www.stackoverflow"

Nếu bạn cần lặp lại các thao tác đó, mở rộng Stringcó thể là một giải pháp tốt:

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")
*/

Các phương pháp KHÔNG yêu cầu Foundation

Nhận một chuỗi con bao gồm chỉ mục cuối cùng của một ký tự:

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

// prints "www.stackoverflow."

Nhận một chuỗi con KHÔNG bao gồm chỉ mục cuối cùng của một ký tự:

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

// prints "www.stackoverflow"

Nếu bạn cần lặp lại các thao tác đó, mở rộng Stringcó thể là một giải pháp tốt:

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

Đây là một cách dễ dàng và ngắn gọn để lấy một chuỗi con nếu bạn biết chỉ mục:

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

Nó sẽ không làm hỏng ứng dụng nếu chỉ mục của bạn vượt quá độ dài của chuỗi:

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

Cả hai ví dụ đều đã sẵn sàng cho Swift 3 .


4

Một điều làm tăng thêm âm thanh là sự lặp lại stringVar :

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

Trong Swift 4

Tiện ích mở rộng có thể giảm bớt một số điều đó:

extension String {

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

Sau đó, cách sử dụng:

let string = "abcde"

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

Cần lưu ý rằng tofromlà loại Substring(hoặc String.SubSequance). Chúng không phân bổ các chuỗi mới và hiệu quả hơn để xử lý.

Để lấy lại một Stringloại, Substringcần phải được chuyển trở lại String:

let backToString = String(from)

Đây là nơi cuối cùng một chuỗi được cấp phát.


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

Swift 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

Bài viết tốt để hiểu, tại sao chúng ta cần điều này


2

Tôi đã mở rộng Chuỗi với hai phương thức chuỗi con. Bạn có thể gọi chuỗi con với phạm vi from / to hoặc from / length như vậy:

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 không còn khả dụng nữa. Bạn cần thêm điều này vào tiện ích mở rộng (Andrewz, vui lòng cập nhật mã; tôi không muốn đăng câu trả lời khác): public func length () -> Int {return self.lengthOfBytesUsingEncoding (NSUTF16StringEncoding)}
philippe

1

Swift 2.0 Đoạn mã dưới đây được thử nghiệm trên XCode 7.2. Vui lòng tham khảo ảnh chụp màn hình đính kèm ở phía dưới

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

Trong Swift 5

Chúng ta cần String.Indexthay vì giá trị Int đơn giản để đại diện cho Chỉ số.

Cũng nên nhớ rằng, khi chúng ta cố gắng lấy chuỗi con từ Swift String(kiểu giá trị), chúng ta thực sự phải lặp lại với Sequencegiao thức, giao thức trả về String.SubSequencekiểu thay vìString kiểu.

Để lấy lại Stringtừ String.SubSequence, sử dụngString(subString)

Ví dụ như bên dưới:

    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

Đối với Swift 2.0 , nó như thế này:

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

Có thể họ đã thay đổi nó, nhưng nó là 'advancedBy' (lưu ý chữ 'd' ở cuối 'advanced')
Wedge Martin

0

Tôi đã sửa đổi bài đăng của andrewz để làm cho nó tương thích với Swift 2.0 (và có thể là Swift 3.0). Theo ý kiến ​​khiêm tốn của tôi, phần mở rộng này dễ hiểu hơn và tương tự như những gì có sẵn trong các ngôn ngữ khác (như 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

Tôi cũng xây dựng một chuỗi mở rộng đơn giản cho 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])
     }
}

Vì vậy, bạn có thể dễ dàng gọi nó như sau:

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

0

Hãy thử Int-basedcách giải quyết này :

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

Lưu ý: Nó chỉ là một thực hành. Nó không kiểm tra ranh giới. Sửa đổi để phù hợp với nhu cầu của bạn.


-1

Đây là một cách đơn giản để lấy chuỗi con trong Swift

import UIKit

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

OP hỏi "Làm thế nào để lấy chuỗi con từ đầu đến chỉ mục cuối cùng của ký tự" chứ không phải làm thế nào để lấy chuỗi con bằng cách sử dụng các giá trị mã cứng được xác định trước.
Eric Aya

Đây là ví dụ ban đầu: chuyển đổi "www.stackoverflow.com" thành "www.stackoverflow". Nếu bạn muốn một chuỗi con từ đầu đến cuối thì không phải làm gì, tức là kết quả là chuỗi đầu vào như hiện tại. Vui lòng khôi phục tính hữu ích của câu trả lời trên.
ZagorTeNej
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.