Swift에서 "Index"를 "Int"유형으로 변환하는 방법은 무엇입니까?


94

문자열에 포함 된 문자의 인덱스를 정수 값으로 변환하고 싶습니다. 헤더 파일을 읽으려고 시도했지만에 대한 유형을 찾을 수 없지만 메서드 (예 Index:)가있는 프로토콜을 준수하는 것으로 보입니다 .ForwardIndexTypedistanceTo

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)

도움을 주시면 감사하겠습니다.


xcode 7.2와 swift 2.x가 있습니까?
— aaisataev 2015

사실 지금 바로 Xcode 7.2를 다운로드하고 있습니다.
— Christopher

33
놀이터에서 원하는 인덱스를 보는 것보다 더 실망스러운 것은 없으며 인덱스를 필요한 종류로 변환하는 것은 거대한 PITA입니다. 나는 차라리 내 곡괭이를 문에 쾅 닫고 싶습니다.
— Adrian

1
Swift 3 : let index = letters.characters.index(of: "c") 다음 라인let int_index = letters.characters.distance(from: letters.startIndex, to: index)
— Viktor

8
애플 WTF !!!!!!
— Borzh

답변:


91

편집 / 업데이트 :

Xcode 11 • Swift 5.1 이상

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

놀이터 테스트

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

49
왜 그들은 배열 요소의 정수 값 인덱스를 반환하는 함수를 만들기로 결정하지 않는 이유가 너무 혼란 스럽습니다. smh
— MarksCode

6
모든 문자를 단일 바이트에 저장할 수있는 것은 아닙니다. 시간을내어 Swift String 문서를 읽어보십시오
— Leo Dabus 2017


4
Tbh 문자열이 아닌 일반 배열 요소의 정수 값 인덱스를 얻으려고합니다.
— MarksCode

28
단순한 일을 불필요하게 복잡하게 만들기 :(
— Iulian Onofrei

4

스위프트 4

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

참고 : 문자열 에 동일한 여러 문자가 포함 된 경우 왼쪽에서 가장 가까운 문자 만 가져옵니다.

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

6
encodingOffset을 사용하지 마십시오. encodingOffset이 더 이상 사용되지 않음 : 대부분의 일반적인 사용이 올바르지 않기 때문에 encodeOffset이 더 이상 사용되지 않습니다. 시도"🇺🇸🇺🇸🇧🇷".index(of: "🇧🇷")?.encodedOffset // 16
— Leo Dabus

@LeoDabus가 더 이상 사용되지 않는다고 올바르게 설명하고 있습니다. 그러나 어쨌든 그것을 대답으로 사용하는 것이 좋습니다. 정답은 다음과 같습니다. index_Of_YourStringVariable.utf16Offset (in : yourStringVariable)
— TDesign

아니요. UTF16 오프셋은 아마도 원하는 것이 아닐 것입니다
— Leo Dabus

1

encodedOffsetSwift 4.2 에서 더 이상 사용되지 않습니다. .

지원 중단 메시지 : encodedOffset가장 일반적인 사용법이 올바르지 않아 더 이상 사용되지 않습니다. 사용하다utf16Offset(in:)동일한 동작을 달성하기 위해 합니다.

따라서 다음 utf16Offset(in:)과 같이 사용할 수 있습니다 .

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

1
시도 let str = "🇺🇸🇺🇸🇧🇷" let index = str.firstIndex(of: "🇧🇷")?.utf16Offset(in: str)// 결과 : 8
— Leo Dabus

0

index를 기반으로 문자열 연산을 수행하려면 기존 인덱스 숫자 방식으로는 수행 할 수 없습니다. swift.index는 indices 함수에 의해 검색되고 Int 유형이 아니기 때문입니다. String이 문자의 배열이지만 인덱스로 요소를 읽을 수는 없습니다.

이것은 실망 스럽습니다.

따라서 string의 모든 짝수 문자의 새 하위 문자열을 만들려면 아래 코드를 확인하십시오.

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)

출력 : acegikmoqsuwy

미리 감사드립니다


이것은 필터를 사용하여 쉽게 수행 할 수 있습니다var counter = 0 let result = mystr.filter { _ in defer { counter += 1 } return counter.isMultiple(of: 2) }
— Leo Dabus

String.index 사용을 선호하는 경우var 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

다음은 값 Int대신 s 로 하위 문자열의 경계에 액세스 할 수 있는 확장 입니다 String.Index.

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

이것이 기이함으로 이어질 수 있다는 점을 명심하십시오. 이것이 Apple이 그것을 어렵게 만들기로 선택한 이유입니다. (논쟁의 여지가있는 디자인 결정이긴하지만-어렵게 만들어 위험한 것을 숨기는 것 ...)

Apple 의 String 문서에서 더 많은 것을 읽을 수 있지만, tldr은 이러한 "인덱스"가 실제로 구현에 따라 다르다는 사실에서 비롯된 것입니다. 그것들은 OS에 의해 렌더링 된 후 문자열에 대한 색인을 나타내 므로 사용중인 유니 코드 사양의 버전에 따라 OS에서 OS로 이동할 수 있습니다. 즉, 문자열에서 올바른 위치를 결정하기 위해 데이터에 대해 UTF 사양을 실행해야하므로 인덱스로 값에 액세스하는 것이 더 이상 상수 시간 작업이 아닙니다. 이러한 인덱스는 NSString에 의해 생성 된 값이나 기본 UTF 스칼라에 대한 인덱스와 함께 정렬되지 않습니다. 주의 사항 개발자.


startIndex에서 거리를 다시 측정 할 필요가 없습니다. 하단에서 상단까지의 거리를 얻고 시작점을 추가하십시오.
— Leo Dabus

나는 또한 당신의 방법에 옵션을 추가 할 것입니다. 같은 것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

아마도 메소드 이름을로 변경 countableRange하고 돌아올 것입니다CountableRange
— Leo Dabus

좋은 제안 @LeoDabus 전반적으로. 실제로 모든 range (of ...) 인수를 추가 했으므로 이제 countableRange (of :, options :, range :, locale :)을 호출 할 수 있습니다. 요점을 업데이트했으며이 게시물도 업데이트합니다.
— Zack

하위 문자열에서 해당 메서드를 호출 할 수 있다는 점을 고려하면 범위가 필요하지 않습니다.
— Leo Dabus

0

이와 같은 색인을 검색 할 때

⛔️ guard let index = (positions.firstIndex { position <= $0 }) else {

Array.Index로 처리됩니다. 컴파일러에게 정수를 원하는 단서를 제공해야합니다.

✅ guard let index: Int = (positions.firstIndex { position <= $0 }) else {
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.