Làm thế nào để chuyển đổi "Index" thành "Int" trong Swift?


91

Tôi muốn chuyển đổi chỉ mục của một chữ cái có trong một chuỗi thành giá trị số nguyên. Đã cố gắng đọc các tệp tiêu đề nhưng tôi không thể tìm thấy loại cho Index, mặc dù nó có vẻ tuân theo giao thức ForwardIndexTypevới các phương thức (ví dụ distanceTo:).

var letters = "abcdefg"
let index = letters.characters.indexOf("c")!

// ERROR: Cannot invoke initializer for type 'Int' with an argument list of type '(String.CharacterView.Index)'
let intValue = Int(index)  // I want the integer value of the index (e.g. 2)

Bất kỳ trợ giúp được đánh giá cao.


bạn có xcode 7.2 và swift 2.x không?
aaisataev

Trên thực tế, tôi đang tải xuống Xcode 7.2 ngay tại thời điểm này.
Christopher

33
Không có gì khó chịu hơn việc nhìn thấy chỉ mục bạn muốn nhìn chằm chằm vào mặt bạn trong một sân chơi và đó là một PITA khổng lồ để chuyển đổi chỉ mục thành loại bạn cần. Tôi thà đập tay vào cửa.
Adrian

1
Swift 3: let index = letters.characters.index(of: "c") Dòng tiếp theolet int_index = letters.characters.distance(from: letters.startIndex, to: index)
Viktor

8
Apple WTF !!!!!!
Borzh

Câu trả lời:


87

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

Xcode 11 • Swift 5.1 trở lên

extension StringProtocol {
    func distance(of element: Element) -> Int? { firstIndex(of: element)?.distance(in: self) }
    func distance<S: StringProtocol>(of string: S) -> Int? { range(of: string)?.lowerBound.distance(in: self) }
}

extension Collection {
    func distance(to index: Index) -> Int { distance(from: startIndex, to: index) }
}

extension String.Index {
    func distance<S: StringProtocol>(in string: S) -> Int { string.distance(to: self) }
}

Thử nghiệm sân chơi

let letters = "abcdefg"

let char: Character = "c"
if let distance = letters.distance(of: char) {
    print("character \(char) was found at position #\(distance)")   // "character c was found at position #2\n"
} else {
    print("character \(char) was not found")
}

let string = "cde"
if let distance = letters.distance(of: string) {
    print("string \(string) was found at position #\(distance)")   // "string cde was found at position #2\n"
} else {
    print("string \(string) was not found")
}

48
Tôi rất bối rối vì sao họ sẽ không chỉ quyết định để thực hiện một chức năng mà trả về chỉ số nguyên có giá trị của nguyên tố .. SMH của một mảng
MarksCode

6
Không phải tất cả các ký tự đều có thể được lưu trữ trong một byte. Bạn nên dành chút thời gian và đọc tài liệu Swift Chuỗi
Leo Dabus


4
Tbh Tôi đang cố lấy chỉ số giá trị nguyên của phần tử của mảng thông thường, không phải là một chuỗi.
Mã MarksCode

28
Làm cho mọi thứ đơn giản không cần thiết phức tạp :(
Iulian Onofrei

4

Swift 4

var str = "abcdefg"
let index = str.index(of: "c")?.encodedOffset // Result: 2

Lưu ý: Nếu Chuỗi chứa nhiều ký tự giống nhau, nó sẽ chỉ lấy ký tự gần nhất từ ​​bên trái

var str = "abcdefgc"
let index = str.index(of: "c")?.encodedOffset // Result: 2

6
Không sử dụng encodedOffset. encodedOffset không được dùng nữa: encodedOffset không được dùng nữa vì cách sử dụng phổ biến nhất là không chính xác. cố gắng"🇺🇸🇺🇸🇧🇷".index(of: "🇧🇷")?.encodedOffset // 16
Leo Dabus

@LeoDabus mà bạn nói chính xác là nó không được dùng nữa. Nhưng dù sao thì bạn cũng đang đề nghị sử dụng nó như một câu trả lời. Câu trả lời đúng là: index_Of_YourStringVariable.utf16Offset (trong: yourStringVariable)
TDesign

Không. UTF16 bù đắp nó có thể không phải là điều bạn muốn
Leo Dabus

1

encodedOffsetđã không còn được sử dụng từ Swift 4.2 .

Thông báo không dùng nữa : encodedOffsetđã không còn được dùng nữa vì hầu hết cách sử dụng phổ biến là không chính xác. Sử dụng utf16Offset(in:)để đạt được cùng một hành vi.

Vì vậy, chúng ta có thể sử dụng utf16Offset(in:)như sau:

var str = "abcdefgc"
let index = str.index(of: "c")?.utf16Offset(in: str) // Result: 2

1
thử let str = "🇺🇸🇺🇸🇧🇷" let index = str.firstIndex(of: "🇧🇷")?.utf16Offset(in: str)// Kết quả: 8
Leo Dabus

0

Để thực hiện hoạt động chuỗi dựa trên chỉ mục, bạn không thể làm điều đó với cách tiếp cận số chỉ mục truyền thống. vì swift.index được truy xuất bởi hàm chỉ số và nó không thuộc kiểu Int. Mặc dù String là một mảng các ký tự, chúng ta vẫn không thể đọc phần tử theo chỉ mục.

Thật là bực bội.

Vì vậy, để tạo chuỗi con mới của mọi ký tự chẵn của chuỗi, hãy kiểm tra mã bên dưới.

let mystr = "abcdefghijklmnopqrstuvwxyz"
let mystrArray = Array(mystr)
let strLength = mystrArray.count
var resultStrArray : [Character] = []
var i = 0
while i < strLength {
    if i % 2 == 0 {
        resultStrArray.append(mystrArray[i])
      }
    i += 1
}
let resultString = String(resultStrArray)
print(resultString)

Đầu ra: acegikmoqsuwy

Cảm ơn trước


điều này có thể dễ dàng thực hiện với bộ lọcvar counter = 0 let result = mystr.filter { _ in defer { counter += 1 } return counter.isMultiple(of: 2) }
Leo Dabus

nếu bạn thích sử dụng String.indexvar index = mystr.startIndex let result = mystr.filter { _ in defer { mystr.formIndex(after: &index) } return mystr.distance(from: mystr.startIndex, to: index).isMultiple(of: 2) }
Leo Dabus

0

Đây là một tiện ích mở rộng sẽ cho phép bạn truy cập các giới hạn của chuỗi con dưới dạng Ints thay vì các String.Indexgiá trị:

import Foundation

/// This extension is available at
/// https://gist.github.com/zackdotcomputer/9d83f4d48af7127cd0bea427b4d6d61b
extension StringProtocol {
    /// Access the range of the search string as integer indices
    /// in the rendered string.
    /// - NOTE: This is "unsafe" because it may not return what you expect if
    ///     your string contains single symbols formed from multiple scalars.
    /// - Returns: A `CountableRange<Int>` that will align with the Swift String.Index
    ///     from the result of the standard function range(of:).
    func countableRange<SearchType: StringProtocol>(
        of search: SearchType,
        options: String.CompareOptions = [],
        range: Range<String.Index>? = nil,
        locale: Locale? = nil
    ) -> CountableRange<Int>? {
        guard let trueRange = self.range(of: search, options: options, range: range, locale: locale) else {
            return nil
        }

        let intStart = self.distance(from: startIndex, to: trueRange.lowerBound)
        let intEnd = self.distance(from: trueRange.lowerBound, to: trueRange.upperBound) + intStart

        return Range(uncheckedBounds: (lower: intStart, upper: intEnd))
    }
}

Chỉ cần lưu ý rằng điều này có thể dẫn đến sự kỳ lạ, đó là lý do tại sao Apple đã chọn làm khó nó. (Mặc dù đó là một quyết định thiết kế gây tranh cãi - che giấu một điều nguy hiểm bằng cách chỉ làm cho nó khó ...)

Bạn có thể đọc thêm trong tài liệu Chuỗi của Apple , nhưng điều quan trọng là nó bắt nguồn từ thực tế là các "chỉ số" này thực sự dành riêng cho việc triển khai. Chúng đại diện cho các chỉ số trong chuỗi sau khi nó được hệ điều hành hiển thị và do đó có thể chuyển từ OS-sang-OS tùy thuộc vào phiên bản của thông số Unicode đang được sử dụng. Điều này có nghĩa là việc truy cập các giá trị theo chỉ mục không còn là một hoạt động liên tục theo thời gian nữa, vì thông số UTF phải được chạy trên dữ liệu để xác định đúng vị trí trong chuỗi. Các chỉ số này cũng sẽ không phù hợp với các giá trị do NSString tạo ra, nếu bạn kết nối với nó hoặc với các chỉ số vào các vô hướng UTF cơ bản. Nhà phát triển báo trước.


không cần phải đo khoảng cách tạo lại startIndex. Chỉ cần lấy khoảng cách từ dưới lên trên và thêm phần bắt đầu.
Leo Dabus

Tôi cũng sẽ thêm các tùy chọn vào phương pháp của bạn. Đại loại làfunc rangeInt<S: StringProtocol>(of aString: S, options: String.CompareOptions = []) -> Range<Int>? { guard let range = range(of: aString, options: options) else { return nil } let start = distance(from: startIndex, to: range.lowerBound) return start..<start+distance(from: range.lowerBound, to: range.upperBound) }
Leo Dabus

Tôi có thể sẽ thay đổi tên phương thức thành countableRangevà quay lạiCountableRange
Leo Dabus

Tất cả các gợi ý hay về @LeoDabus. Trên thực tế, tôi đã thêm tất cả các đối số range (of ...), vì vậy bây giờ bạn có thể gọi countableRange (of :, options :, range :, locale :). Đã cập nhật Gist, sẽ cập nhật bài đăng này nữa.
Zack

Tôi không cần phạm vi vì bạn có thể gọi phương thức đó trên một chuỗi con
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.