Làm thế nào để bạn sử dụng String.subopesWithRange? (hoặc, Ranges hoạt động như thế nào trong Swift?)


266

Tôi vẫn chưa thể tìm ra cách lấy chuỗi con của StringSwift:

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

Tôi không thể tạo Phạm vi trong Swift. Tự động hoàn tất trong Sân chơi không phải là siêu hữu ích - đây là những gì nó gợi ý:

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

Tôi không tìm thấy bất cứ điều gì trong Thư viện tham khảo tiêu chuẩn Swift giúp. Đây là một phỏng đoán hoang dã khác:

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

Và điều này:

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

Tôi đã thấy các câu trả lời khác ( Tìm chỉ mục của ký tự trong Chuỗi Swift ) dường như gợi ý rằng vì đây Stringlà loại cầu nối NSString, nên các phương thức "cũ" sẽ hoạt động, nhưng không rõ bằng cách nào - ví dụ: điều này cũng không hoạt động ( không có vẻ là cú pháp hợp lệ):

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

Suy nghĩ?


Ý bạn là gì khi bạn nói ví dụ cuối cùng không hoạt động? Nó có gây ra lỗi hoặc trả về giá trị không mong muốn không?
67 quả anh đào

Hãy gạt rdar: // 17158813 yêu cầu subscript ký hiệu openradar.appspot.com/radar?id=6373877630369792
Rob Napier

Câu trả lời:


259

Bạn có thể sử dụng phương thức chuỗi conWithRange. Nó bắt đầu và kết thúc String.Index.

var str = "Hello, playground"
str.substringWithRange(Range<String.Index>(start: str.startIndex, end: str.endIndex)) //"Hello, playground"

Để thay đổi chỉ số bắt đầu và kết thúc, hãy sử dụng advancedBy (n).

var str = "Hello, playground"
str.substringWithRange(Range<String.Index>(start: str.startIndex.advancedBy(2), end: str.endIndex.advancedBy(-1))) //"llo, playgroun"

Bạn cũng vẫn có thể sử dụng phương pháp NSString với NSRange, nhưng bạn phải chắc chắn rằng bạn đang sử dụng một NSString như thế này:

let myNSString = str as NSString
myNSString.substringWithRange(NSRange(location: 0, length: 3))

Lưu ý: như JanX2 đã đề cập, phương thức thứ hai này không an toàn với các chuỗi unicode.


5
Vâng. Cho đến bây giờ tôi vẫn tiếp tục bắc cầu đến NSString khi cần thiết. Có vẻ như Chuỗi của Swift vẫn chưa hoàn thành
Connor

14
Điều này không an toàn! Bạn đang giả sử rằng các chỉ mục thành Chuỗi và NSString có thể hoán đổi cho nhau. Đó không phải là tình huống. Các chỉ mục thành Chuỗi liên quan đến các điểm mã Unicode trong khi các chỉ mục thành một NSString đề cập đến các đơn vị mã UTF-16! Hãy thử nó với biểu tượng cảm xúc.
JanX2

3
Xin lưu ý rằng Chỉ mục thành Chuỗi không tham chiếu đến các điểm mã Unicode nữa. Hãy nghĩ về họ như tham khảo các nhân vật nhận thức người dùng.
JanX2

2
Vậy câu trả lời đúng ở đây là gì? Gọi advancecó nghĩa là chúng ta phải lặp lại toàn bộ thông qua một chuỗi dài có thể. Nhưng hình thành một NSRange và sử dụng NSString rõ ràng có nguy hiểm không? Những gì còn lại?
matt

1
Cảm ơn, m8. Quá trình chuyển đổi sang Swift này khá lộn xộn sau 4 năm chỉ thực hiện Objective-C.
Felipe

162

Swift 2

Đơn giản

let str = "My String"
let subStr = str[str.startIndex.advancedBy(3)...str.startIndex.advancedBy(7)]
//"Strin"

Swift 3

let startIndex = str.index(str.startIndex, offsetBy: 3)
let endIndex = str.index(str.startIndex, offsetBy: 7)

str[startIndex...endIndex]       // "Strin"
str.substring(to: startIndex)    // "My "
str.substring(from: startIndex)  // "String"

Swift 4

substring(to:)substring(from:)đang bị phản đối trong Swift 4.

String(str[..<startIndex])    // "My "
String(str[startIndex...])    // "String"
String(str[startIndex...endIndex])    // "Strin"

2
ĐIỀU NÀY. Thật khó hiểu khi bạn phải tìm chỉ mục của mình trước khi bạn có thể sử dụng nó. Không biết tại sao tôi mất quá nhiều thời gian để nhận ra, nhưng cảm ơn vì sự đóng góp của bạn cho loại người.
Warpzit

1
Trong swift 4 hoạt động chuỗi con trả về một thể hiện của loại Chuỗi con, thay vì Chuỗi. Cần chuyển đổi kết quả thành Chuỗi để lưu trữ lâu dài. hãy để newString = String (chuỗi con)
phnmnn

43

LƯU Ý: @airspeedswift đưa ra một số điểm rất sâu sắc về sự đánh đổi của phương pháp này, đặc biệt là các tác động hiệu suất ẩn. Các chuỗi không phải là các con thú đơn giản và việc đi đến một chỉ mục cụ thể có thể mất thời gian O (n), điều đó có nghĩa là một vòng lặp sử dụng một chỉ mục có thể là O (n ^ 2). Bạn đã được cảnh báo.

Bạn chỉ cần thêm một subscriptchức năng mới có phạm vi và sử dụng advancedBy()để đi bộ đến nơi bạn muốn:

import Foundation

extension String {
    subscript (r: Range<Int>) -> String {
        get {
            let startIndex = self.startIndex.advancedBy(r.startIndex)
            let endIndex = startIndex.advancedBy(r.endIndex - r.startIndex)

            return self[Range(start: startIndex, end: endIndex)]
        }
    }
}

var s = "Hello, playground"

println(s[0...5]) // ==> "Hello,"
println(s[0..<5]) // ==> "Hello"

(Điều này chắc chắn phải là một phần của ngôn ngữ. Vui lòng lừa đảo : // 17158813 )

Để giải trí, bạn cũng có thể thêm +toán tử vào các chỉ mục:

func +<T: ForwardIndex>(var index: T, var count: Int) -> T {
  for (; count > 0; --count) {
    index = index.succ()
  }
  return index
}

s.substringWithRange(s.startIndex+2 .. s.startIndex+5)

(Tôi chưa biết liệu đây có phải là một phần của ngôn ngữ hay không.)


2
Có lẽ chúng ta nên làm việc với String.Index thay vì các chỉ số nguyên càng nhiều càng tốt vì lý do hiệu suất. Mỗi chuyển đổi từ một chỉ mục số nguyên thành String.Index cần xử lý chuỗi để tìm kiếm.
JanX2

11
@AndrewDunn Đây không phải là tối ưu hóa sớm. Mỗi chuyển đổi từ một chỉ số nguyên thành Chuỗi. Index là O (n), không phải O (1)! Xin vui lòng đọc các ý kiến ​​cho advance<T>(…)trong Swiftkhông gian tên.
JanX2

1
Toàn bộ việc thực hiện String được thực hiện bằng cách sử dụng String.Index. Trong trường hợp này, nó không tối ưu hóa nhiều như nó đang giữ mọi thứ đơn giản. Phải tung hứng giữa int và String. Index qua lại ở mọi nơi sẽ dẫn đến một mớ hỗn độn.
chakrit

@chakrit Chỉ khi các chỉ mục bạn cần sử dụng chưa có số nguyên (thay vì là String.Indexes) thường xảy ra. Hơn bạn chỉ có thể muốn tất cả các phương thức xử lý chuỗi đã làm việc với Ints. Và bạn buộc phải hội tụ nó String.Indexesdẫn đến sự lộn xộn mà bạn đề cập.
Rasto

Người đọc quan tâm nên xem qua ExSwift github.com/pNre/ExSwift
AsTeR

42

Tại thời điểm tôi đang viết, không có tiện ích mở rộng nào tương thích hoàn toàn với Swift 4.2 , vì vậy đây là một tiện ích đáp ứng tất cả các nhu cầu tôi có thể nghĩ đến:

extension String {
    func substring(from: Int?, to: Int?) -> String {
        if let start = from {
            guard start < self.count else {
                return ""
            }
        }

        if let end = to {
            guard end >= 0 else {
                return ""
            }
        }

        if let start = from, let end = to {
            guard end - start >= 0 else {
                return ""
            }
        }

        let startIndex: String.Index
        if let start = from, start >= 0 {
            startIndex = self.index(self.startIndex, offsetBy: start)
        } else {
            startIndex = self.startIndex
        }

        let endIndex: String.Index
        if let end = to, end >= 0, end < self.count {
            endIndex = self.index(self.startIndex, offsetBy: end + 1)
        } else {
            endIndex = self.endIndex
        }

        return String(self[startIndex ..< endIndex])
    }

    func substring(from: Int) -> String {
        return self.substring(from: from, to: nil)
    }

    func substring(to: Int) -> String {
        return self.substring(from: nil, to: to)
    }

    func substring(from: Int?, length: Int) -> String {
        guard length > 0 else {
            return ""
        }

        let end: Int
        if let start = from, start > 0 {
            end = start + length - 1
        } else {
            end = length - 1
        }

        return self.substring(from: from, to: end)
    }

    func substring(length: Int, to: Int?) -> String {
        guard let end = to, end > 0, length > 0 else {
            return ""
        }

        let start: Int
        if let end = to, end - length > 0 {
            start = end - length + 1
        } else {
            start = 0
        }

        return self.substring(from: start, to: to)
    }
}

Và sau đó, bạn có thể sử dụng:

let string = "Hello,World!"

string.substring(from: 1, to: 7)giúp bạn ello,Wo

string.substring(to: 7)giúp bạn Hello,Wo

string.substring(from: 3)giúp bạn lo,World!

string.substring(from: 1, length: 4)giúp bạn ello

string.substring(length: 4, to: 7)giúp bạn o,Wo

Cập nhật substring(from: Int?, length: Int)để hỗ trợ bắt đầu từ số không.


Làm thế nào điều này xử lý biểu tượng cảm xúc và cụm grapheme mở rộng? (Tôi nên tự mình kiểm tra nhưng nó không thuận tiện vào lúc này.)
Suragch

2
@Suragch Nó xử lý nó OK: "Hello😇😍😘😎📸📀💾∝ℵℶ≹".substring(from: 4, to: 14)cung cấp cho chúng tôi:o😇😍😘😎📸📀💾∝ℵℶ
mùa đông

Những người trông giống như nhân vật bình thường, mặc dù. Hãy thử sử dụng biểu tượng cảm xúc như hoặc
Supuhstar

31

Chuyển đổi 2.0

đơn giản:

let myString = "full text container"
let substring = myString[myString.startIndex..<myString.startIndex.advancedBy(3)] // prints: ful

Chuyển đổi 3.0

let substring = myString[myString.startIndex..<myString.index(myString.startIndex, offsetBy: 3)] // prints: ful

Chuyển đổi 4.0

Các hoạt động của chuỗi con trả về một thể hiện của loại Chuỗi con, thay vì Chuỗi.

let substring = myString[myString.startIndex..<myString.index(myString.startIndex, offsetBy: 3)] // prints: ful

// Convert the result to a String for long-term storage.
let newString = String(substring)

4
Không còn tương thích với Swift 3 kể từ Xcode 8 beta 6, thật đáng buồn
Ben Morrow

1
Làm việc cho tôi. Xcode 8, Swift 3. Không phải beta trên Mac OS Sierra. text[text.startIndex..<text.index(text.startIndex, offsetBy: 2)]
Jose Ramirez

18

Nó đơn giản hơn nhiều so với bất kỳ câu trả lời nào ở đây, một khi bạn tìm đúng cú pháp.

Tôi muốn lấy đi [và]

let myString = "[ABCDEFGHI]"
let startIndex = advance(myString.startIndex, 1) //advance as much as you like
let endIndex = advance(myString.endIndex, -1)
let range = startIndex..<endIndex
let myNewString = myString.substringWithRange( range )

kết quả sẽ là "ABCDEFGHI", start Index và end Index cũng có thể được sử dụng trong

let mySubString = myString.substringFromIndex(startIndex)

và như thế!

PS: Như đã nêu trong phần nhận xét, có một số thay đổi cú pháp trong swift 2 đi kèm với xcode 7 và iOS9!

Hãy nhìn vào trang này


Có, tôi đã có cùng một vấn đề với trình gỡ lỗi không hiển thị chuỗi chính xác nhiều lần?
dùng1700737

tôi có một chuỗi như thế này / Ngày (147410000000) /. Làm thế nào tôi có thể nhận được giá trị thay vì chỉ định chỉ mục. Tôi cần nhận giá trị bằng RangeOfString ("(") và RangeOfString (")"). Kết quả sẽ là 147410000000. Tôi có thể lấy nó không
iPhone Guy

Điều đó không quá khó: var str = "/ Ngày (147410000000) /." var phạm vi = str.rangeOfString ( "(") !. endIndex .. <str.rangeOfString ( ")") !. startIndex hãy myNewString = str.substringWithRange (range)
user1700737

4
kể từ advance(myString.endIndex, -1)cú pháp Xcode 7 beta 6 đã thay đổi thànhmyString.endIndex.advancedBy(-1)
l --marc l

16

Ví dụ: để tìm tên đầu tiên (tối đa khoảng trắng đầu tiên) trong tên đầy đủ của tôi:

let name = "Joris Kluivers"

let start = name.startIndex
let end = find(name, " ")

if end {
    let firstName = name[start..end!]
} else {
    // no space found
}

startendcó kiểu String.Indexở đây và được sử dụng để tạo một Range<String.Index>và được sử dụng trong trình truy cập chỉ mục (nếu một khoảng trống được tìm thấy trong chuỗi gốc).

Thật khó để tạo String.Indextrực tiếp từ một vị trí số nguyên như được sử dụng trong bài mở đầu. Điều này là do trong tên của tôi, mỗi ký tự sẽ có kích thước bằng byte. Nhưng các ký tự sử dụng dấu đặc biệt trong các ngôn ngữ khác có thể đã sử dụng nhiều byte hơn (tùy thuộc vào mã hóa được sử dụng). Vậy số nguyên nên tham chiếu đến byte nào?

Có thể tạo một cái mới String.Indextừ một cái hiện có bằng các phương thức succpredđiều này sẽ đảm bảo số byte chính xác được bỏ qua để đến điểm mã tiếp theo trong mã hóa. Tuy nhiên, trong trường hợp này, việc tìm kiếm chỉ mục của khoảng trắng đầu tiên trong chuỗi để tìm chỉ mục kết thúc sẽ dễ dàng hơn.


16

Vì Chuỗi là loại cầu nối cho NSString, nên các phương thức "cũ" sẽ hoạt động, nhưng không rõ bằng cách nào - ví dụ: điều này cũng không hoạt động (dường như không phải là cú pháp hợp lệ):

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

Đối với tôi, đó là phần thực sự thú vị trong câu hỏi của bạn. Chuỗi được bắc cầu đến NSString, vì vậy hầu hết các phương thức NSString đều hoạt động trực tiếp trên Chuỗi. Bạn có thể sử dụng chúng một cách tự do và không cần suy nghĩ. Vì vậy, ví dụ, điều này hoạt động như bạn mong đợi:

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

Nhưng, như thường xảy ra, "Tôi đã làm việc với mojo của mình nhưng nó không hoạt động với bạn." Bạn tình cờ chọn một trong những trường hợp hiếm hoi tồn tại phương thức Swift có tên giống hệt nhau và trong trường hợp như vậy, phương thức Swift làm lu mờ phương thức Objective-C. Do đó, khi bạn nói str.substringWithRange, Swift nghĩ rằng bạn có nghĩa là phương pháp Swift chứ không phải là phương pháp NSString - và sau đó bạn bị hos, bởi vì phương thức Swift mong đợi một Range<String.Index>, và bạn không biết cách tạo ra một trong số đó.

Cách dễ dàng là ngăn Swift làm lu mờ như thế này, bằng cách sử dụng một cách rõ ràng:

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

Lưu ý rằng không có việc làm thêm đáng kể có liên quan ở đây. "Diễn viên" không có nghĩa là "chuyển đổi"; Chuỗi thực sự một NSString. Chúng tôi chỉ nói cho Swift cách xem biến này cho các mục đích của một dòng mã này.

Phần thực sự kỳ lạ của toàn bộ điều này là phương pháp Swift, gây ra tất cả những rắc rối này, không có giấy tờ. Tôi không biết nó được định nghĩa ở đâu; nó không nằm trong tiêu đề NSString và nó cũng không nằm trong tiêu đề Swift.


Tuy nhiên, tôi đề nghị nộp một lỗi. Apple nên "câu cá hoặc cắt mồi" - hoặc cho chúng tôi cách xây dựng Range<String.Index>hoặc đưa phương pháp không có giấy tờ này ra khỏi đường đi của chúng tôi.
matt

Chết tiệt - cái này hữu ích. Mặc dù tài liệu nói gì, tôi không hiểu chuyện gì đang xảy ra cho đến khi tôi đọc nó. Bây giờ đã được sắp xếp :)
Jon M

13

Trong Xcode 7.0 mới sử dụng

//: Playground - noun: a place where people can play

import UIKit

var name = "How do you use String.substringWithRange?"
let range = name.startIndex.advancedBy(0)..<name.startIndex.advancedBy(10)
name.substringWithRange(range)

//OUT:

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


2
.advancedBy(0) không cần thiết cho start Index.
Mat0

12

Câu trả lời ngắn gọn là điều này thực sự khó khăn trong Swift ngay bây giờ. Linh cảm của tôi là vẫn còn một loạt công việc để Apple thực hiện các phương pháp tiện lợi cho những thứ như thế này.

String.substringWithRange()đang mong đợi một Range<String.Index>tham số, và theo như tôi có thể nói là không có phương thức tạo cho String.Indexloại. Bạn có thể nhận String.Indexcác giá trị sao lưu từ aString.startIndexaString.endIndexvà cuộc gọi .succ()hoặc .pred()vào chúng, nhưng điều đó điên rồ của.

Làm thế nào về một phần mở rộng trên lớp String có Ints cũ tốt ?

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

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

let dogString = "This 🐶's name is Patch."
println(dogString[5..<6])               // 🐶
println(dogString[5...5])              // 🐶
println(dogString.substring(5))        // 🐶's name is Patch.
println(dogString.substring(5, length: 1))   // 🐶

Cập nhật: Swift beta 4 giải quyết các vấn đề bên dưới!

Vì nó đứng [trong phiên bản beta 3 trở về trước], ngay cả các chuỗi gốc Swift cũng có một số vấn đề với việc xử lý các ký tự Unicode. Biểu tượng con chó ở trên đã hoạt động, nhưng sau đây không:

let harderString = "1:1️⃣"
for character in harderString {
    println(character)
}

Đầu ra:

1
:
1
️
⃣

1
Thật kỳ lạ, các lớp Swift cốt lõi dường như thiếu rất nhiều chức năng cơ bản. Tôi không thể nghĩ rằng Apple muốn chúng tôi liên tục tham khảo các lớp Foundation để thực hiện các nhiệm vụ đơn giản.
bluedevil2k

1
Tổng cộng. Hãy nhớ rằng Swift về cơ bản được phát triển trong bóng tối và mọi người có một định nghĩa khác nhau về "các nhiệm vụ đơn giản" - Tôi cá là chúng ta sẽ thấy một số bước lặp nhanh chóng về các vấn đề này.
Nate Cook

@ JanX2 - Cảm ơn, bạn hoàn toàn đúng. Cầu nối liền mạch NSStringkhiến tôi nghĩ rằng tôi chỉ sử dụng các Stringphương thức gốc của Swift , vì tôi không sử dụng bất kỳ myString as NSStringcuộc gọi nào .
Nate Cook

Ngay bây giờ cũng có một số lỗi Unicode trong xử lý chuỗi gốc Swift: xem phần ghi chú của tôi ở cuối.
Nate Cook

@NateCook Bạn có thể vui lòng gửi một radar cho vấn đề đó?
JanX2

11

Bạn có thể sử dụng tiện ích mở rộng này để cải thiện substringWithRange

Swift 2.3

extension String
{   
    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(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 str = "Hello, playground"

let substring1 = str.substringWithRange(0, end: 5) //Hello
let substring2 = str.substringWithRange(7, location: 10) //playground

7

Mã mẫu để biết cách lấy chuỗi con trong Swift 2.0

(i) Chuỗi con từ chỉ mục bắt đầu

Đầu vào:-

var str = "Swift is very powerful language!"
print(str)

str = str.substringToIndex(str.startIndex.advancedBy(5))
print(str)

Đầu ra: -

Swift is very powerful language!
Swift

(ii) Chuỗi con từ chỉ mục cụ thể

Đầu vào:-

var str = "Swift is very powerful language!"
print(str)

str = str.substringFromIndex(str.startIndex.advancedBy(6)).substringToIndex(str.startIndex.advancedBy(2))
print(str)

Đầu ra: -

Swift is very powerful language!
is

Tôi hy vọng nó sẽ giúp bạn!


7

Giải pháp dễ dàng với ít mã.

Tạo một tiện ích mở rộng bao gồm SubStringing cơ bản mà gần như tất cả các ngôn ngữ khác có:

extension String {
    func subString(start: Int, end: Int) -> String {
        let startIndex = self.index(self.startIndex, offsetBy: start)
        let endIndex = self.index(startIndex, offsetBy: end)

        let finalString = self.substring(from: startIndex)
        return finalString.substring(to: endIndex)
    }
}

Đơn giản chỉ cần gọi nó với

someString.subString(start: 0, end: 6)

1
Tham số 'end' thực sự có nghĩa là độ dài ở đây vì vậy tôi nghĩ nó nên được đổi tên thành đó.
Jovan Jovanovski

Tôi nghĩ rằng sử dụng chiều dài là khá khó hiểu. Trên thực tế, đó là 'kết thúc' của nơi bạn muốn có SubString, chứ không phải độ dài thực tế của kết quả SubStrings.
Oliver Dixon

6

Điều này hoạt động trong sân chơi của tôi :)

String(seq: Array(str)[2...4])

Trên thực tế, việc này hiệu quả hơn so với gọi điệnadvance
Erik Aigner

2
Nó không hoạt động trong sân chơi Xcode 7 (Swift 2) của tôi, nhưng điều này không ... 'var str = "Xin chào, sân chơi"' Chuỗi (Mảng (str.char character) [7]) // "p" Chuỗi (Mảng (Mảng (Array) str.char character) [7 ... 10]) // "play" String (Array (str.char character) [7 .. <10]) // "pla"
Vince O'Sullivan

6

Đã cập nhật cho Xcode 7. Thêm tiện ích mở rộng Chuỗi:

Sử dụng:

var chuck: String = "Hello Chuck Norris"
chuck[6...11] // => Chuck

Thực hiện:

extension String {

    /**
     Subscript to allow for quick String substrings ["Hello"][0...1] = "He"
     */
    subscript (r: Range<Int>) -> String {
        get {
            let start = self.startIndex.advancedBy(r.startIndex)
            let end = self.startIndex.advancedBy(r.endIndex - 1)
            return self.substringWithRange(start..<end)
        }
    }

}

4

thử cái này trong sân chơi

var str:String = "Hello, playground"

let range = Range(start:advance(str.startIndex,1), end: advance(str.startIndex,8))

nó sẽ cung cấp cho bạn "ello, p"

Tuy nhiên, điều này thực sự thú vị là nếu bạn tạo chỉ mục cuối cùng lớn hơn chuỗi trong sân chơi, nó sẽ hiển thị bất kỳ chuỗi nào bạn đã xác định sau str: o

Range () dường như là một hàm chung để nó cần biết loại mà nó đang xử lý.

Bạn cũng phải cung cấp cho nó chuỗi thực sự mà bạn quan tâm đến các sân chơi vì nó dường như giữ tất cả các chuỗi theo thứ tự lần lượt với tên biến sau đó.

Vì thế

var str:String = "Hello, playground"

var str2:String = "I'm the next string"

let range = Range(start:advance(str.startIndex,1), end: advance(str.startIndex,49))

đưa ra "ello, sân chơi strTôi là chuỗi tiếp theo str2 "

hoạt động ngay cả khi str2 được định nghĩa bằng lệnh let

:)


Tôi đồng ý rằng nó dài dòng so với Objective-C, tuy nhiên tất cả đều phù hợp với một dòng là phần thưởng.
Peter Roberts

Chà, vẫn còn một dòng bị thiếu thực sự in ra chuỗi con cho phạm vi bạn đã tính. Tôi thích một số giải pháp khác tạo các phần mở rộng lớp String bằng logic của bạn, nhưng trong phần mở rộng. Đó cuối cùng là giải pháp tôi đã đi cùng.
Roderic Campbell

Họ đã sửa lỗi mà bạn có thể vượt ra ngoài cuối chuỗi. Bây giờ bạn chỉ có thể đặt một giá trị cho đến str.end Index
Peter Roberts

4

Rob Napier đã đưa ra một câu trả lời tuyệt vời bằng cách sử dụng đăng ký. Nhưng tôi cảm thấy một nhược điểm trong đó là không có kiểm tra cho các điều kiện ràng buộc. Điều này có thể có xu hướng sụp đổ. Vì vậy, tôi đã sửa đổi phần mở rộng và đây là

extension String {
    subscript (r: Range<Int>) -> String? { //Optional String as return value
        get {
            let stringCount = self.characters.count as Int
            //Check for out of boundary condition
            if (stringCount < r.endIndex) || (stringCount < r.startIndex){
                return nil
            }
            let startIndex = self.startIndex.advancedBy(r.startIndex)

            let endIndex = self.startIndex.advancedBy(r.endIndex - r.startIndex)

            return self[Range(start: startIndex, end: endIndex)]
        }
    }
}

Đầu ra bên dưới

var str2 = "Hello, World"

var str3 = str2[0...5]
//Hello,
var str4 = str2[0..<5]
//Hello
var str5 = str2[0..<15]
//nil

Vì vậy, tôi đề nghị luôn luôn kiểm tra nếu cho phép

if let string = str[0...5]
{
    //Manipulate your string safely
}

Bạn đã có một lỗi ở đó - end Index nên được bắt đầu nâng cao chỉ bằng end Index chứ không phải khoảng cách giữa các chỉ số.
Aviad Ben Dov

3

Trong Swift3

Ví dụ: một biến "Duke James Thomas", chúng ta cần lấy "James".

let name = "Duke James Thomas"
let range: Range<String.Index> = name.range(of:"James")!
let lastrange: Range<String.Index> = img.range(of:"Thomas")!
var middlename = name[range.lowerBound..<lstrange.lowerBound]
print (middlename)

2

Lấy một trang từ Rob Napier, tôi đã phát triển các Phần mở rộng chuỗi chung này , hai trong số đó là:

subscript (r: Range<Int>) -> String
{
    get {
        let startIndex = advance(self.startIndex, r.startIndex)
        let endIndex = advance(self.startIndex, r.endIndex - 1)

        return self[Range(start: startIndex, end: endIndex)]
    }
}

func subString(startIndex: Int, length: Int) -> String
{
    var start = advance(self.startIndex, startIndex)
    var end = advance(self.startIndex, startIndex + length)
    return self.substringWithRange(Range<String.Index>(start: start, end: end))
}

Sử dụng:

"Awesome"[3...7] //"some"
"Awesome".subString(3, length: 4) //"some"

Bạn có thể sử dụng Rangethay vì Range<String.Index>cảm ơn kiểu suy luận.
Dan Rosenstark

2

Đây là cách bạn có được một phạm vi từ một chuỗi:

var str = "Hello, playground"

let startIndex = advance(str.startIndex, 1)
let endIndex = advance(startIndex, 8)
let range = startIndex..<endIndex
let substr = str[range] //"ello, pl"

Điểm mấu chốt là bạn đang chuyển một phạm vi các giá trị của loại String.Index (đây là giá trị trả trước) thay vì số nguyên.

Lý do tại sao điều này là cần thiết, là vì các chuỗi trong Swift không có quyền truy cập ngẫu nhiên (về cơ bản là do các ký tự Unicode có độ dài thay đổi). Bạn cũng không thể làm được str[1]. String.Index được thiết kế để làm việc với cấu trúc bên trong của chúng.

Tuy nhiên, bạn có thể tạo một tiện ích mở rộng với một chỉ mục, điều này phù hợp với bạn, vì vậy bạn chỉ có thể vượt qua một loạt các số nguyên (xem ví dụ câu trả lời của Rob Napier ).


2

Tôi đã cố gắng đưa ra một cái gì đó Pythonic.

Tất cả các mục đăng ký ở đây đều tuyệt vời, nhưng những lúc tôi thực sự cần thứ gì đó đơn giản thường là khi tôi muốn đếm ngược lại, vd string.endIndex.advancedBy(-1)

Nó hỗ trợ nilcác giá trị, cho cả chỉ mục bắt đầu và kết thúc, trong đó nilcó nghĩa là chỉ số ở mức 0 cho bắt đầu, string.characters.countcho kết thúc.

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

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

let dog = "Dog‼🐶"
print(dog.subString(nil)(-1)) // Dog!!

BIÊN TẬP

Một giải pháp thanh lịch hơn:

public extension String {
    struct Substring {
        var start: Int?
        var string: String

        public subscript(end: Int?) -> String {
            let startIndex = start ?? 0 < 0 ? string.endIndex.advancedBy(start!) : string.startIndex.advancedBy(start ?? 0)
            let endIndex = end ?? string.characters.count < 0 ? string.endIndex.advancedBy(end!) : string.startIndex.advancedBy(end ?? string.characters.count)

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

    public subscript(start: Int?) -> Substring {
        return Substring(start: start, string: self)
    }
}

let dog = "Dog‼🐶"
print(dog[nil][-1]) // Dog!!

1

Đầu tiên tạo phạm vi, sau đó là chuỗi con. Bạn có thể sử dụng fromIndex..<toIndexcú pháp như vậy:

let range = fullString.startIndex..<fullString.startIndex.advancedBy(15) // 15 first characters of the string
let substring = fullString.substringWithRange(range)

1

đây là một ví dụ để chỉ nhận Id video .ie (6oL687G0Iso) từ toàn bộ URL trong swift

let str = "https://www.youtube.com/watch?v=6oL687G0Iso&list=PLKmzL8Ib1gsT-5LN3V2h2H14wyBZTyvVL&index=2"
var arrSaprate = str.componentsSeparatedByString("v=")
let start = arrSaprate[1]
let rangeOfID = Range(start: start.startIndex,end:start.startIndex.advancedBy(11))
let substring = start[rangeOfID]
print(substring)

1
let startIndex = text.startIndex
var range = startIndex.advancedBy(1) ..< text.endIndex.advancedBy(-4)
let substring = text.substringWithRange(range)

Mẫu đầy đủ bạn có thể xem ở đây



0

Chà, tôi đã có cùng một vấn đề và đã giải quyết với hàm "BridgeToObjectiveC ()":

var helloworld = "Hello World!"
var world = helloworld.bridgeToObjectiveC().substringWithRange(NSMakeRange(6,6))
println("\(world)") // should print World!

Xin lưu ý rằng trong ví dụ, chuỗi conWithRange kết hợp với NSMakeRange lấy phần của chuỗi bắt đầu từ chỉ số 6 (ký tự "W") và hoàn thành ở vị trí chỉ số 6 + 6 phía trước (ký tự "!")

Chúc mừng.


Tôi ghét điều này, nhưng đó là điều duy nhất có vẻ hiệu quả với tôi trong Beta 4.
Roderic Campbell

0

Bạn có thể sử dụng bất kỳ phương thức chuỗi con nào trong tiện ích mở rộng Chuỗi Swift tôi đã viết https://bit.ly/JString .

var string = "hello"
var sub = string.substringFrom(3) // or string[3...5]
println(sub)// "lo"

0

Nếu bạn có một NSRange, bắc cầu để NSStringlàm việc liền mạch. Ví dụ, tôi đang thực hiện một số công việc UITextFieldDelegatevà tôi nhanh chóng muốn tính giá trị chuỗi mới khi nó hỏi liệu nó có nên thay thế phạm vi không.

func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
    let newString = (textField.text as NSString).stringByReplacingCharactersInRange(range, withString: string)
    println("Got new string: ", newString)
}

0

Tiện ích mở rộng đơn giản cho String:

extension String {

    func substringToIndex(index: Int) -> String {
        return self[startIndex...startIndex.advancedBy(min(index, characters.count - 1))]
    }
}

0

Nếu bạn không quan tâm đến hiệu suất ... đây có lẽ là giải pháp ngắn gọn nhất trong Swift 4

extension String {
    subscript(range: CountableClosedRange<Int>) -> String {
        return enumerated().filter{$0.offset >= range.first! && $0.offset < range.last!}
            .reduce(""){$0 + String($1.element)}
    }
}

Nó cho phép bạn làm một cái gì đó như thế này:

let myStr = "abcd"
myStr[0..<2] // produces "ab"
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.