Chuỗi con String hoạt động như thế nào trong Swift


354

Tôi đã cập nhật một số mã và câu trả lời cũ của mình với Swift 3 nhưng khi tôi đến Swift String và Lập chỉ mục với chuỗi con thì mọi thứ trở nên khó hiểu.

Cụ thể tôi đã thử như sau:

let str = "Hello, playground"
let prefixRange = str.startIndex..<str.startIndex.advancedBy(5)
let prefix = str.substringWithRange(prefixRange)

trong đó dòng thứ hai đã cho tôi lỗi sau

Giá trị của loại 'Chuỗi' không có thành viên 'chuỗi conWithRange'

Tôi thấy rằng Stringbây giờ có các phương pháp sau:

str.substring(to: String.Index)
str.substring(from: String.Index)
str.substring(with: Range<String.Index>)

Chúng thực sự làm tôi bối rối lúc đầu nên tôi bắt đầu chơi xung quanh chỉ số và phạm vi . Đây là một câu hỏi và câu trả lời tiếp theo cho chuỗi con. Tôi đang thêm một câu trả lời dưới đây để cho thấy chúng được sử dụng như thế nào.


2
Dành cho những ai muốn lấy chuỗi con từ chuỗi stackoverflow.com/q/32305891/468724
Inder Kumar Rathore

hoặc chuỗi đăng ký hoặc chuỗi con stackoverflow.com/questions/24092884/ từ
Leo Dabus

Câu trả lời:


831

nhập mô tả hình ảnh ở đây

Tất cả các ví dụ sau sử dụng

var str = "Hello, playground"

Swift 4

Chuỗi có một đại tu khá lớn trong Swift 4. Khi bạn nhận được một số chuỗi con từ Chuỗi bây giờ, bạn sẽ nhận được một Substringkiểu trở lại thay vì a String. Tại sao lại thế này? Chuỗi là loại giá trị trong Swift. Điều đó có nghĩa là nếu bạn sử dụng một Chuỗi để tạo một Chuỗi mới, thì nó phải được sao chép lại. Điều này tốt cho sự ổn định (không ai khác sẽ thay đổi nó mà bạn không biết) nhưng lại không tốt cho hiệu quả.

Mặt khác, một Chuỗi con là một tham chiếu trở lại Chuỗi ban đầu mà nó xuất hiện. Dưới đây là một hình ảnh từ tài liệu minh họa rằng.

Không cần sao chép nên sử dụng hiệu quả hơn nhiều. Tuy nhiên, hãy tưởng tượng bạn có một Chuỗi con mười ký tự từ Chuỗi triệu ký tự. Vì Chuỗi con đang tham chiếu Chuỗi, nên hệ thống sẽ phải giữ toàn bộ Chuỗi miễn là Chuỗi con ở xung quanh. Do đó, bất cứ khi nào bạn hoàn thành thao tác Chuỗi con của mình, hãy chuyển đổi nó thành Chuỗi.

let myString = String(mySubstring)

Điều này sẽ chỉ sao chép chuỗi con qua và bộ nhớ giữ Chuỗi cũ có thể được lấy lại . Chất nền (như một loại) có nghĩa là sống ngắn.

Một cải tiến lớn khác trong Swift 4 là Chuỗi là Bộ sưu tập (một lần nữa). Điều đó có nghĩa là bất cứ điều gì bạn có thể làm với Bộ sưu tập, bạn có thể làm với Chuỗi (sử dụng các mục con, lặp lại qua các ký tự, bộ lọc, v.v.).

Các ví dụ sau đây cho thấy cách lấy chuỗi con trong Swift.

Bắt chất nền

Bạn có thể lấy một chuỗi con từ một chuỗi bằng cách sử dụng kí hiệu hoặc một số phương pháp khác (ví dụ, prefix, suffix, split). Bạn vẫn cần sử dụng String.Indexvà không phải là một Intchỉ mục cho phạm vi. (Xem câu trả lời khác của tôi nếu bạn cần giúp đỡ về điều đó.)

Bắt đầu một chuỗi

Bạn có thể sử dụng một mục con (lưu ý phạm vi một phía của Swift 4):

let index = str.index(str.startIndex, offsetBy: 5)
let mySubstring = str[..<index] // Hello

hoặc prefix:

let index = str.index(str.startIndex, offsetBy: 5)
let mySubstring = str.prefix(upTo: index) // Hello

hoặc thậm chí dễ dàng hơn:

let mySubstring = str.prefix(5) // Hello

Kết thúc chuỗi

Sử dụng đăng ký:

let index = str.index(str.endIndex, offsetBy: -10)
let mySubstring = str[index...] // playground

hoặc suffix:

let index = str.index(str.endIndex, offsetBy: -10)
let mySubstring = str.suffix(from: index) // playground

hoặc thậm chí dễ dàng hơn:

let mySubstring = str.suffix(10) // playground

Lưu ý rằng khi sử dụng suffix(from: index)tôi phải đếm lại từ cuối bằng cách sử dụng -10. Điều đó là không cần thiết khi chỉ sử dụng suffix(x), chỉ cần lấy các xký tự cuối cùng của Chuỗi.

Phạm vi trong một chuỗi

Một lần nữa chúng tôi chỉ đơn giản là sử dụng đăng ký ở đây.

let start = str.index(str.startIndex, offsetBy: 7)
let end = str.index(str.endIndex, offsetBy: -6)
let range = start..<end

let mySubstring = str[range]  // play

Chuyển đổi SubstringsangString

Đừng quên, khi bạn đã sẵn sàng lưu chuỗi con của mình, bạn nên chuyển đổi nó thành một Stringbộ nhớ để chuỗi cũ có thể được dọn sạch.

let myString = String(mySubstring)

Sử dụng một Intphần mở rộng chỉ mục?

Tôi ngần ngại sử dụng Inttiện ích mở rộng chỉ mục dựa trên sau khi đọc bài viết Chuỗi trong Swift 3 của Airspeed Velocity và Ole Begemann. Mặc dù trong Swift 4, String là các bộ sưu tập, nhóm Swift cố tình không sử dụng Intcác chỉ mục. Nó vẫn còn String.Index. Điều này có liên quan đến các Nhân vật Swift được tạo thành từ các số lượng khác nhau của các loại tiền mã hóa Unicode. Chỉ số thực tế phải được tính toán duy nhất cho mỗi chuỗi.

Tôi phải nói rằng, tôi hy vọng nhóm Swift tìm ra cách để trừu tượng hóa String.Indextrong tương lai. Nhưng cho đến khi họ chọn sử dụng API của họ. Nó giúp tôi nhớ rằng các thao tác Chuỗi không chỉ là Inttra cứu chỉ mục đơn giản .


9
Thx cho sự giải thích. Rất xứng đáng uprates. Apple đã quá phức tạp điều này. Chuỗi con phải dễ dàng như chuỗi.sub chuỗi [từ ... đến].
Teddy

Giải thích thực sự tốt. ngoại trừ một điều nhỏ garbage collected;-) Tôi hy vọng mọi người ở đây biết rằng không có bộ sưu tập rác trong Swift.
Christian Anchor Dampf

@ChristianAnchorDampf, Cảm ơn bạn đã dành thời gian để bình luận. Tôi lấy ra thu gom rác. Từ ngữ mới như thế nào?
Suragch

Thật là một câu trả lời tuyệt vời thưa ngài !!
davidev

194

Tôi thực sự thất vọng về mô hình truy cập Chuỗi của Swift: mọi thứ phải là một Index. Tất cả những gì tôi muốn là truy cập vào ký tự thứ i của chuỗi bằng cách sử dụng Int, chứ không phải chỉ số vụng về và tiến bộ (điều này sẽ thay đổi với mỗi bản phát hành chính). Vì vậy, tôi đã thực hiện một phần mở rộng để String:

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

    func substring(from: Int) -> String {
        let fromIndex = index(from: from)
        return String(self[fromIndex...])
    }

    func substring(to: Int) -> String {
        let toIndex = index(from: to)
        return String(self[..<toIndex])
    }

    func substring(with r: Range<Int>) -> String {
        let startIndex = index(from: r.lowerBound)
        let endIndex = index(from: r.upperBound)
        return String(self[startIndex..<endIndex])
    }
}

let str = "Hello, playground"
print(str.substring(from: 7))         // playground
print(str.substring(to: 5))           // Hello
print(str.substring(with: 7..<11))    // play

5
Các chỉ mục rất hữu ích vì một ký tự có thể nhiều hơn một byte. Hãy thửlet str = "🇨🇭🇩🇪🇺🇸Hello" print(str.substring(to: 2))
vadian

110
Có, tôi hiểu rằng một ký tự (tức là cụm grapheme mở rộng ) có thể mất nhiều byte. Sự thất vọng của tôi là lý do tại sao chúng ta phải sử dụng phương pháp tiến bộ chỉ mục dài dòng để truy cập các ký tự của chuỗi. Tại sao nhóm Swift không thể thêm một số quá tải vào Thư viện lõi để trừu tượng hóa nó. Nếu tôi gõ str[5], tôi muốn truy cập vào ký tự ở chỉ mục 5, bất kể ký tự đó có vẻ là gì hoặc mất bao nhiêu byte. Không phải Swift là tất cả về năng suất của nhà phát triển sao?
Mã khác nhau

6
@RenniePet Tôi tin rằng Apple nhận ra vấn đề và những thay đổi đang đến. Theo trang Swift Evolution trên GitHub: "Swift 4 tìm cách làm cho các chuỗi mạnh hơn và dễ sử dụng hơn, trong khi vẫn giữ chính xác Unicode theo mặc định". Thật mơ hồ nhưng chúng ta hãy giữ hy vọng của mình
Mã khác

3
@CodeDifferent tại sao apple không thêm quyền truy cập ký tự phụ? Để mọi người hiểu rằng đó là điều xấu để làm. Về cơ bản nếu bạn sẽ làm cho i trong 0..opes.count bằng cách sử dụng các chỉ số sẽ là vòng lặp kép, vì chỉ số mui xe phải đi qua từng byte của chuỗi để tìm ra ký tự tiếp theo. Nếu bạn lặp bằng chỉ mục, bạn chỉ lặp qua chuỗi một lần. Btw, ghét bản thân tôi, nhưng đó là lý do đằng sau đăng ký không có sẵn trên chuỗi nhanh chóng.
Raimundas Sakalauskas

4
@RaimundasSakalauskas cuộc tranh luận đó không bay theo tôi. C # có cả tính chính xác Unicode và đăng ký số nguyên, điều này thực sự tiện lợi. Trong Swift 1, Apple muốn các nhà phát triển sử dụng countElement(str)để tìm độ dài. Trong Swift 3, Apple đã tạo ra chuỗi không tuân thủ Sequencevà buộc mọi người phải sử dụng str.charactersthay thế. Những kẻ này không sợ thay đổi. Sự bướng bỉnh của họ đối với việc đăng ký số nguyên thực sự khó hiểu
Mã khác nhau

102

Tiện ích mở rộng Swift 5:

extension String {
    subscript(_ range: CountableRange<Int>) -> String {
        let start = index(startIndex, offsetBy: max(0, range.lowerBound))
        let end = index(start, offsetBy: min(self.count - range.lowerBound, 
                                             range.upperBound - range.lowerBound))
        return String(self[start..<end])
    }

    subscript(_ range: CountablePartialRangeFrom<Int>) -> String {
        let start = index(startIndex, offsetBy: max(0, range.lowerBound))
         return String(self[start...])
    }
}

Sử dụng:

let s = "hello"
s[0..<3] // "hel"
s[3...]  // "lo"

Hoặc unicode:

let s = "😎🤣😋"
s[0..<1] // "😎"

2
Vì vậy, tốt hơn nhiều, cảm ơn bạn đã đăng phần mở rộng này! Tôi nghĩ rằng đến từ Python, Swift khó hơn nhiều so với cần thiết để làm quen. Dường như đối với những người đi theo hướng khác từ Objective C sang Swift thì có sự xác nhận tích cực hơn.
dùng3064009

1
@Leon tôi mới gỡ nó ra. Trước 4.1, countchỉ có sẵn trênself.characters
Lou Zell

1
Có bất kỳ vấn đề nào để xem với phần mở rộng đặc biệt này không? Tại sao Apple không làm điều gì đó như thế này?
Andz

1
@Andz nó rất kém hiệu quả. Nó bắt đầu từ đầu chuỗi - hai lần - và phải phân tích từng ký tự từ đó đến "phạm vi" - hai lần.
kareman

3
Bạn cũng cần thêm một tiện ích mở rộngCountableClosedRange<Int> nếu bạn muốn viết ví dụ s[0...2].
Chris Frederick

24

Swift 4 & 5:

extension String {
  subscript(_ i: Int) -> String {
    let idx1 = index(startIndex, offsetBy: i)
    let idx2 = index(idx1, offsetBy: 1)
    return String(self[idx1..<idx2])
  }

  subscript (r: Range<Int>) -> String {
    let start = index(startIndex, offsetBy: r.lowerBound)
    let end = index(startIndex, offsetBy: r.upperBound)
    return String(self[start ..< end])
  }

  subscript (r: CountableClosedRange<Int>) -> String {
    let startIndex =  self.index(self.startIndex, offsetBy: r.lowerBound)
    let endIndex = self.index(startIndex, offsetBy: r.upperBound - r.lowerBound)
    return String(self[startIndex...endIndex])
  }
}

Làm thế nào để sử dụng nó:

"abcde" [0] -> "a"

"abcde" [0 ... 2] -> "abc"

"abcde" [2 .. <4] -> "cd"


20

Swift 4

Trong swift 4 Stringphù hợp với Collection. Thay vì substring, bây giờ chúng ta nên sử dụng một subscript.Vì vậy, nếu bạn muốn cắt ra chỉ từ "play"từ "Hello, playground", bạn có thể làm điều đó như thế này:

var str = "Hello, playground"
let start = str.index(str.startIndex, offsetBy: 7)
let end = str.index(str.endIndex, offsetBy: -6)
let result = str[start..<end] // The result is of type Substring

Thật thú vị khi biết rằng làm như vậy sẽ cung cấp cho bạn một Substringthay vì a String. Điều này nhanh và hiệu quả khi Substringchia sẻ lưu trữ của nó với Chuỗi ban đầu. Tuy nhiên, chia sẻ bộ nhớ theo cách này cũng có thể dễ dàng dẫn đến rò rỉ bộ nhớ.

Đây là lý do tại sao bạn nên sao chép kết quả vào một Chuỗi mới, một khi bạn muốn dọn sạch Chuỗi ban đầu. Bạn có thể làm điều này bằng cách sử dụng hàm tạo thông thường:

let newString = String(result)

Bạn có thể tìm thêm thông tin về Substringlớp mới trong [Tài liệu của Apple]. 1

Vì vậy, nếu bạn lấy ví dụ Rangelà kết quả của một NSRegularExpression, bạn có thể sử dụng tiện ích mở rộng sau:

extension String {

    subscript(_ range: NSRange) -> String {
        let start = self.index(self.startIndex, offsetBy: range.lowerBound)
        let end = self.index(self.startIndex, offsetBy: range.upperBound)
        let subString = self[start..<end]
        return String(subString)
    }

}

Mã của bạn sẽ sập nếu phạm vi.upperBound là> độ dài của chuỗi. Ngoài ra, việc sử dụng mẫu cũng rất hữu ích vì tôi không quen với các mục đăng ký trong Swift. Bạn có thể bao gồm một cái gì đó như datePartOnly = "2018-01-04-08: 00" [NSMakeRange (0, 10)]. Ngoài ra, câu trả lời rất hay, +1 :).
dcp

ngày nay nó là điều kỳ lạ: text[Range( nsRange , in: text)!]
Fattie

10

Đây là một hàm trả về chuỗi con của một chuỗi con đã cho khi các chỉ số bắt đầu và kết thúc được cung cấp. Để tham khảo đầy đủ, bạn có thể truy cập các liên kết được đưa ra dưới đây.

func substring(string: String, fromIndex: Int, toIndex: Int) -> String? {
    if fromIndex < toIndex && toIndex < string.count /*use string.characters.count for swift3*/{
        let startIndex = string.index(string.startIndex, offsetBy: fromIndex)
        let endIndex = string.index(string.startIndex, offsetBy: toIndex)
        return String(string[startIndex..<endIndex])
    }else{
        return nil
    }
}

Đây là một liên kết đến bài đăng blog mà tôi đã tạo để đối phó với thao tác chuỗi trong swift. Thao tác chuỗi trong swift (Bao gồm cả swift 4)

Hoặc bạn có thể thấy ý chính này trên github


9

Tôi đã có phản ứng ban đầu tương tự. Tôi cũng thất vọng về cách cú pháp và các đối tượng thay đổi mạnh mẽ như vậy trong mỗi bản phát hành chính.

Tuy nhiên, tôi nhận ra từ kinh nghiệm về việc cuối cùng tôi luôn phải chịu hậu quả của việc cố gắng chống lại "sự thay đổi" như xử lý các ký tự nhiều byte là điều không thể tránh khỏi nếu bạn nhìn vào khán giả toàn cầu.

Vì vậy, tôi quyết định công nhận và tôn trọng những nỗ lực của các kỹ sư Apple và thực hiện phần của tôi bằng cách hiểu được suy nghĩ của họ khi họ đưa ra phương pháp "khủng khiếp" này.

Thay vì tạo các tiện ích mở rộng chỉ là một cách giải quyết để làm cho cuộc sống của bạn dễ dàng hơn (tôi không nói là chúng sai hay đắt tiền), tại sao bạn không tìm hiểu cách String hiện được thiết kế để hoạt động.

Chẳng hạn, tôi đã có mã này đang hoạt động trên Swift 2.2:

let rString = cString.substringToIndex(2)
let gString = (cString.substringFromIndex(2) as NSString).substringToIndex(2)
let bString = (cString.substringFromIndex(4) as NSString).substringToIndex(2)

và sau khi từ bỏ việc cố gắng làm cho cách tiếp cận tương tự hoạt động, ví dụ như sử dụng Substrings, cuối cùng tôi đã hiểu khái niệm coi Chuỗi là một bộ sưu tập hai chiều mà tôi đã kết thúc với phiên bản cùng mã này:

let rString = String(cString.characters.prefix(2))
cString = String(cString.characters.dropFirst(2))
let gString = String(cString.characters.prefix(2))
cString = String(cString.characters.dropFirst(2))
let bString = String(cString.characters.prefix(2))

Tôi hy vọng điều này đóng góp ...


1
Chà, đối phó với một vấn đề phức tạp không có nghĩa là giải pháp đó có thể thanh lịch. Một lần nữa, tôi cũng hiểu vấn đề, nhưng toàn bộ lớp String và xử lý nó chỉ là khủng khiếp.
inexcitus

5

Cùng một nỗi thất vọng, điều này không nên khó đến thế ...

Tôi đã biên soạn ví dụ này về việc nhận vị trí cho (các) chuỗi con từ văn bản lớn hơn:

//
// Play with finding substrings returning an array of the non-unique words and positions in text
//
//

import UIKit

let Bigstring = "Why is it so hard to find substrings in Swift3"
let searchStrs : Array<String>? = ["Why", "substrings", "Swift3"]

FindSubString(inputStr: Bigstring, subStrings: searchStrs)


func FindSubString(inputStr : String, subStrings: Array<String>?) ->    Array<(String, Int, Int)> {
    var resultArray : Array<(String, Int, Int)> = []
    for i: Int in 0...(subStrings?.count)!-1 {
        if inputStr.contains((subStrings?[i])!) {
            let range: Range<String.Index> = inputStr.range(of: subStrings![i])!
            let lPos = inputStr.distance(from: inputStr.startIndex, to: range.lowerBound)
            let uPos = inputStr.distance(from: inputStr.startIndex, to: range.upperBound)
            let element = ((subStrings?[i])! as String, lPos, uPos)
            resultArray.append(element)
        }
    }
    for words in resultArray {
        print(words)
    }
    return resultArray
}

trả về ("Tại sao", 0, 3) ("chuỗi con", 26, 36) ("Swift3", 40, 46)


3
Đó là một số mã, nhưng không thực sự giải thích cách lập chỉ mục chuỗi và chuỗi con hoạt động trong swift3.
Robert

5

Tôi là người mới trong Swift 3, nhưng tìm kiếm Stringcú pháp (index) cho sự tương tự Tôi nghĩ rằng chỉ mục đó giống như một "con trỏ" bị ràng buộc với chuỗi và Int có thể giúp như một đối tượng độc lập. Sử dụng cú pháp cơ sở + offset, sau đó chúng ta có thể nhận được ký tự thứ i từ chuỗi với mã dưới đây:

let s = "abcdefghi"
let i = 2
print (s[s.index(s.startIndex, offsetBy:i)])
// print c

Đối với một phạm vi các ký tự (chỉ mục) từ chuỗi bằng cú pháp Chuỗi (phạm vi), chúng ta có thể nhận được từ các ký tự thứ i đến thứ f với mã dưới đây:

let f = 6
print (s[s.index(s.startIndex, offsetBy:i )..<s.index(s.startIndex, offsetBy:f+1 )])
//print cdefg

Đối với một chuỗi con (phạm vi) từ một chuỗi bằng String.sub chuỗi (phạm vi), chúng ta có thể nhận được chuỗi con bằng cách sử dụng mã dưới đây:

print (s.substring (with:s.index(s.startIndex, offsetBy:i )..<s.index(s.startIndex, offsetBy:f+1 ) ) )
//print cdefg

Ghi chú:

  1. I-th và f-th bắt đầu bằng 0.

  2. Đối với f-th, tôi sử dụng offsetBY: f + 1, vì phạm vi sử dụng đăng ký .. <(toán tử nửa mở), không bao gồm vị trí f-th.

  3. Tất nhiên phải bao gồm các lỗi xác nhận như chỉ mục không hợp lệ.


5

Swift 4+

extension String {
    func take(_ n: Int) -> String {
        guard n >= 0 else {
            fatalError("n should never negative")
        }
        let index = self.index(self.startIndex, offsetBy: min(n, self.count))
        return String(self[..<index])
    }
}

Trả về một chuỗi con của n ký tự đầu tiên hoặc toàn bộ chuỗi nếu chuỗi ngắn hơn. (lấy cảm hứng từ: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.text/take.html )

Thí dụ:

let text = "Hello, World!"
let substring = text.take(5) //Hello

4

Tôi khá suy nghĩ máy móc. Dưới đây là những điều cơ bản ...

Swift 4 Swift 5

  let t = "abracadabra"

  let start1 = t.index(t.startIndex, offsetBy:0)
  let   end1 = t.index(t.endIndex, offsetBy:-5)
  let start2 = t.index(t.endIndex, offsetBy:-5)
  let   end2 = t.index(t.endIndex, offsetBy:0)

  let t2 = t[start1 ..< end1]
  let t3 = t[start2 ..< end2]                

  //or a shorter form 

  let t4 = t[..<end1]
  let t5 = t[start2...]

  print("\(t2) \(t3) \(t)")
  print("\(t4) \(t5) \(t)")

  // result:
  // abraca dabra abracadabra

Kết quả là một chuỗi con, có nghĩa là nó là một phần của chuỗi gốc. Để có được một chuỗi riêng biệt đầy đủ, chỉ cần sử dụng ví dụ

    String(t3)
    String(t4)

Đây là những gì tôi sử dụng:

    let mid = t.index(t.endIndex, offsetBy:-5)
    let firstHalf = t[..<mid]
    let secondHalf = t[mid...]

3

Swift 4

extension String {
    subscript(_ i: Int) -> String {
        let idx1 = index(startIndex, offsetBy: i)
        let idx2 = index(idx1, offsetBy: 1)
        return String(self[idx1..<idx2])
    }
}

let s = "hello"

s[0]    // h
s[1]    // e
s[2]    // l
s[3]    // l
s[4]    // o

2

Tôi đã tạo một tiện ích mở rộng đơn giản cho việc này (Swift 3)

extension String {
    func substring(location: Int, length: Int) -> String? {
        guard characters.count >= location + length else { return nil }
        let start = index(startIndex, offsetBy: location)
        let end = index(startIndex, offsetBy: location + length)
        return substring(with: start..<end)
    }
}

2

Đây là một triển khai chung hơn:

Kỹ thuật này vẫn sử dụng indexđể tuân thủ các tiêu chuẩn của Swift và ngụ ý một Nhân vật đầy đủ.

extension String
{
    func subString <R> (_ range: R) -> String? where R : RangeExpression, String.Index == R.Bound
    {
        return String(self[range])
    }

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

Để chuỗi phụ từ ký tự thứ 3:

let item = "Fred looks funny"
item.subString(item.index(at: 2)...) // "ed looks funny"

Tôi đã sử dụng lạc đà subStringđể chỉ ra nó trả về a Stringchứ không phải a Substring.


2

Dựa vào những điều trên tôi cần phải tách một chuỗi ở một ký tự không in, bỏ ký tự không in. Tôi đã phát triển hai phương pháp:

var str = "abc\u{1A}12345sdf"
let range1: Range<String.Index> = str.range(of: "\u{1A}")!
let index1: Int = str.distance(from: str.startIndex, to: range1.lowerBound)
let start = str.index(str.startIndex, offsetBy: index1)
let end = str.index(str.endIndex, offsetBy: -0)
let result = str[start..<end] // The result is of type Substring
let firstStr = str[str.startIndex..<range1.lowerBound]

mà tôi kết hợp sử dụng một số câu trả lời ở trên.

Bởi vì Chuỗi là một bộ sưu tập nên tôi đã làm như sau:

var fString = String()
for (n,c) in str.enumerated(){

*if c == "\u{1A}" {
    print(fString);
    let lString = str.dropFirst(n + 1)
    print(lString)
    break
   }
 fString += String(c)
}*

Mà đối với tôi là trực quan hơn. Cái nào là tốt nhất? Tôi không có cách nào để nói Cả hai đều làm việc với Swift 5


Cảm ơn câu trả lời của bạn. Có điều gì khác về String trong Swift 5 không? Tôi chưa có thời gian để chơi với nó.
Suragch

Họ nói như vậy nhưng tôi chưa có cơ hội để xem xét nó.
Jeremy Andrew

1

Swift 4

"Chuỗi con" ( https://developer.apple.com/documentation/swift/subopes ):

let greeting = "Hi there! It's nice to meet you! 👋"
let endOfSentence = greeting.index(of: "!")!
let firstSentence = greeting[...endOfSentence]
// firstSentence == "Hi there!"

Ví dụ về chuỗi mở rộng:

private typealias HowDoYouLikeThatElonMusk = String
private extension HowDoYouLikeThatElonMusk {

    subscript(_ from: Character?, _ to: Character?, _ include: Bool) -> String? {
        if let _from: Character = from, let _to: Character = to {
            let dynamicSourceForEnd: String = (_from == _to ? String(self.reversed()) : self)
            guard let startOfSentence: String.Index = self.index(of: _from),
                let endOfSentence: String.Index = dynamicSourceForEnd.index(of: _to) else {
                return nil
            }

            let result: String = String(self[startOfSentence...endOfSentence])
            if include == false {
                guard result.count > 2 else {
                        return nil
                }
                return String(result[result.index(result.startIndex, offsetBy: 1)..<result.index(result.endIndex, offsetBy: -1)])
            }
            return result
        } else if let _from: Character = from {
            guard let startOfSentence: String.Index = self.index(of: _from) else {
                return nil
            }
            let result: String = String(self[startOfSentence...])
            if include == false {
                guard result.count > 1 else {
                    return nil
                }
                return String(result[result.index(result.startIndex, offsetBy: 1)...])
            }
            return result
        } else if let _to: Character = to {
            guard let endOfSentence: String.Index = self.index(of: _to) else {
                    return nil
            }
            let result: String = String(self[...endOfSentence])
            if include == false {
                guard result.count > 1 else {
                    return nil
                }
                return String(result[..<result.index(result.endIndex, offsetBy: -1)])
            }
            return result
        }
        return nil
    }
}

ví dụ về việc sử dụng Chuỗi mở rộng:

let source =                                   ">>>01234..56789<<<"
// include = true
var from =          source["3", nil, true]  //       "34..56789<<<"
var to =            source[nil, "6", true]  // ">>>01234..56"
var fromTo =        source["3", "6", true]  //       "34..56"
let notFound =      source["a", nil, true]  // nil
// include = false
from =              source["3", nil, false] //        "4..56789<<<"
to =                source[nil, "6", false] // ">>>01234..5"
fromTo =            source["3", "6", false] //        "4..5"
let outOfBounds =   source[".", ".", false] // nil

let str = "Hello, playground"
let hello = str[nil, ",", false] // "Hello"

-1

Swift 5
let desiredIndex: Int = 7 let substring = str[String.Index(encodedOffset: desiredIndex)...]
Biến chuỗi con này sẽ cho bạn kết quả.
Đơn giản ở đây Int được chuyển đổi thành Index và sau đó bạn có thể chia chuỗi. Trừ khi bạn sẽ nhận được lỗi.


2
Cái này sai. Một ký tự có thể bao gồm một hoặc nhiều byte. Nó chỉ hoạt động với văn bản ascii.
Leo Dabus
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.