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이 그것을 어렵게 만들기로 선택한 이유입니다. (논쟁의 여지가있는 디자인 결정이긴하지만-어렵게 만들어 위험한 것을 숨기는 것 ...)

AppleString 문서에서 더 많은 것을 읽을 수 있지만, 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.