web-dev-qa-db-ja.com

Swiftプログラミング言語で文字列のn番目の文字を取得する

文字列のn番目の文字を取得する方法私は幸運にもブラケット([])アクセサを試してみました。

var string = "Hello, world!"

var firstChar = string[0] // Throws error

エラー: '添え字'は利用できません:文字列にIntを添え字で付けることはできません。

367
Mohsen

注意: Swift 4の適切な実装については Leo Dabusの答え をご覧ください。

スイフト4

Swift 4ではSubstring型が導入され、元の文字列と記憶域を共有することで部分文字列をより高速かつ効率的にしています。そのため、添え字関数が返すべきものです。

試してみる ここ

extension String {
  subscript (i: Int) -> Character {
    return self[index(startIndex, offsetBy: i)]
  }
  subscript (bounds: CountableRange<Int>) -> Substring {
    let start = index(startIndex, offsetBy: bounds.lowerBound)
    let end = index(startIndex, offsetBy: bounds.upperBound)
    return self[start ..< end]
  }
  subscript (bounds: CountableClosedRange<Int>) -> Substring {
    let start = index(startIndex, offsetBy: bounds.lowerBound)
    let end = index(startIndex, offsetBy: bounds.upperBound)
    return self[start ... end]
  }
  subscript (bounds: CountablePartialRangeFrom<Int>) -> Substring {
    let start = index(startIndex, offsetBy: bounds.lowerBound)
    let end = index(endIndex, offsetBy: -1)
    return self[start ... end]
  }
  subscript (bounds: PartialRangeThrough<Int>) -> Substring {
    let end = index(startIndex, offsetBy: bounds.upperBound)
    return self[startIndex ... end]
  }
  subscript (bounds: PartialRangeUpTo<Int>) -> Substring {
    let end = index(startIndex, offsetBy: bounds.upperBound)
    return self[startIndex ..< end]
  }
}
extension Substring {
  subscript (i: Int) -> Character {
    return self[index(startIndex, offsetBy: i)]
  }
  subscript (bounds: CountableRange<Int>) -> Substring {
    let start = index(startIndex, offsetBy: bounds.lowerBound)
    let end = index(startIndex, offsetBy: bounds.upperBound)
    return self[start ..< end]
  }
  subscript (bounds: CountableClosedRange<Int>) -> Substring {
    let start = index(startIndex, offsetBy: bounds.lowerBound)
    let end = index(startIndex, offsetBy: bounds.upperBound)
    return self[start ... end]
  }
  subscript (bounds: CountablePartialRangeFrom<Int>) -> Substring {
    let start = index(startIndex, offsetBy: bounds.lowerBound)
    let end = index(endIndex, offsetBy: -1)
    return self[start ... end]
  }
  subscript (bounds: PartialRangeThrough<Int>) -> Substring {
    let end = index(startIndex, offsetBy: bounds.upperBound)
    return self[startIndex ... end]
  }
  subscript (bounds: PartialRangeUpTo<Int>) -> Substring {
    let end = index(startIndex, offsetBy: bounds.upperBound)
    return self[startIndex ..< end]
  }
}

SubstringStringに変換するために、あなたは単にString(string[0..2])をすることができます、しかし、あなたが周りの部分文字列を維持することを計画する場合にだけそうするべきです。そうでなければ、それをSubstringにしたほうが効率的です。

誰かがこれら2つの拡張を1つにマージするための良い方法を見つけ出すことができれば素晴らしいでしょう。 StringProtocolメソッドが存在しないため、indexを無理に拡張しようとしました。

スイフト3:

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

なぜこれが組み込まれていないのですか?

アップルは以下の説明を提供しています( ここにあります ):

整数を含む文字列の添字は使用できません。

「文字列内のi番目の文字」という概念は、ライブラリやシステムコンポーネントによって解釈が異なります。ユースケースと関連するAPIに従って正しい解釈を選択する必要があるため、Stringは整数で添え字を付けることはできません。

Swiftは、文字列内に格納されている文字データにアクセスするためのいくつかの異なる方法を提供します。

  • String.utf8は、文字列内のUTF-8コード単位のコレクションです。文字列をUTF-8に変換するときにこのAPIを使用します。ほとんどのPOSIX APIは、文字列をUTF-8コード単位で処理します。

  • String.utf16は、文字列形式のUTF-16コード単位のコレクションです。ほとんどのCocoaおよびCocoa touch APIは、文字列をUTF-16コード単位で処理します。たとえば、NSRangeおよびNSAttributedStringとともに使用されるNSRegularExpressionのインスタンスは、UTF-16コード単位で部分文字列のオフセットと長さを格納します。

  • String.unicodeScalarsは、Unicodeスカラーのコレクションです。このAPIは、文字データを低レベルで操作しているときに使用します。

  • String.charactersは、拡張された書記素クラスタの集合です。これは、ユーザーが認識した文字の近似です。

人間が読めるテキストを含む文字列を処理するときは、文字単位の処理はできるだけ避けるべきです。代わりに、String.localizedStandardCompare()String.localizedLowercaseStringString.localizedStandardRangeOfString()など、ロケールに応じた高レベルのUnicodeアルゴリズムを使用してください。

529
aleclarson

Swift 4.2以前

let str = "abcdef"
str[1 ..< 3] // returns "bc"
str[5] // returns "f"
str[80] // returns ""
str.substring(fromIndex: 3) // returns "def"
str.substring(toIndex: str.length - 2) // returns "abcd"

あなたはあなたのプロジェクトにこの文字列拡張子を追加する必要があるでしょう(それは完全にテストされています):

extension String {

  var length: Int {
    return count
  }

  subscript (i: Int) -> String {
    return self[i ..< i + 1]
  }

  func substring(fromIndex: Int) -> String {
    return self[min(fromIndex, length) ..< length]
  }

  func substring(toIndex: Int) -> String {
    return self[0 ..< max(0, toIndex)]
  }

  subscript (r: Range<Int>) -> String {
    let range = Range(uncheckedBounds: (lower: max(0, min(length, r.lowerBound)),
                                        upper: min(length, max(0, r.upperBound))))
    let start = index(startIndex, offsetBy: range.lowerBound)
    let end = index(start, offsetBy: range.upperBound - range.lowerBound)
    return String(self[start ..< end])
  }

}

Swiftは常にこの問題を解決するために用意されていますが(以下に提供する文字列拡張子はありません)、それでも 強くすることを強くお勧めします 。どうして?これは、Stringの構文がほとんどすべてのリリースで変更されていたSwiftの初期のバージョンからの移行にかかる時間を数十時間節約するためでしたが、必要なことは拡張コードの実装を更新することだけでした。アプリ。あなたの選択をしてください。

let str = "Hello, world!"
let index = str.index(str.startIndex, offsetBy: 4)
str[index] // returns Character 'o'

let endIndex = str.index(str.endIndex, offsetBy:-2)
str[index ..< endIndex] // returns String "o, worl"

String(str.suffix(from: index)) // returns String "o, world!"
String(str.prefix(upTo: index)) // returns String "Hell"
307
NAlexN

私はちょうどこのきちんとした回避策を思い付きました

var firstChar = Array(string)[0]
123
Jens Wirth

整数を使用した索引付けは行わず、String.Indexを使用するだけです。主に線形の複雑さを伴います。 String.Indexから範囲を作成し、それを使って部分文字列を取得することもできます。

Swift 3.0

let firstChar = someString[someString.startIndex]
let lastChar = someString[someString.index(before: someString.endIndex)]
let charAtIndex = someString[someString.index(someString.startIndex, offsetBy: 10)]

let range = someString.startIndex..<someString.index(someString.startIndex, offsetBy: 10)
let substring = someString[range]

Swift 2.x

let firstChar = someString[someString.startIndex]
let lastChar = someString[someString.endIndex.predecessor()]
let charAtIndex = someString[someString.startIndex.advanceBy(10)]

let range = someString.startIndex..<someString.startIndex.advanceBy(10)
let subtring = someString[range]

ある文字列から別の文字列へ作成されたインデックス(または範囲)は使用できません。

let index10 = someString.startIndex.advanceBy(10)

//will compile
//sometimes it will work but sometimes it will crash or result in undefined behaviour
let charFromAnotherString = anotherString[index10]
122
Sulthan

Swift 4.1以降

Swift 4のStringProtocolを拡張して、添え字を部分文字列でも使用できるようにすることができます。注:提案により SE-0191IndexDistance == Intへの拡張制約は削除することができます。

extension StringProtocol {

    subscript(offset: Int) -> Element {
        return self[index(startIndex, offsetBy: offset)]
    }

    subscript(_ range: CountableRange<Int>) -> SubSequence {
        return prefix(range.lowerBound + range.count)
            .suffix(range.count)
    }
    subscript(range: CountableClosedRange<Int>) -> SubSequence {
        return prefix(range.lowerBound + range.count)
            .suffix(range.count)
    }

    subscript(range: PartialRangeThrough<Int>) -> SubSequence {
        return prefix(range.upperBound.advanced(by: 1))
    }
    subscript(range: PartialRangeUpTo<Int>) -> SubSequence {
        return prefix(range.upperBound)
    }
    subscript(range: PartialRangeFrom<Int>) -> SubSequence {
        return suffix(Swift.max(0, count - range.lowerBound))
    }
}

extension LosslessStringConvertible {
    var string: String { return String(self) }
}

extension BidirectionalCollection {
    subscript(safe offset: Int) -> Element? {
        guard !isEmpty, let i = index(startIndex, offsetBy: offset, limitedBy: index(before: endIndex)) else { return nil }
        return self[i]
    }
}

テスト

let test = "Hello USA ????????!!! Hello Brazil ????????!!!"
test[safe: 10]   // "????????"
test[11]   // "!"
test[10...]   // "????????!!! Hello Brazil ????????!!!"
test[10..<12]   // "????????!"
test[10...12]   // "????????!!"
test[...10]   // "Hello USA ????????"
test[..<10]   // "Hello USA "
test.first   // "H"
test.last    // "!"

// Subscripting the Substring
 test[...][...3]  // "Hell"

// Note that they all return a Substring of the original String.
// To create a new String you need to add .string as follow
test[10...].string  // "????????!!! Hello Brazil ????????!!!"
94
Leo Dabus

スイフト4

let str = "My String"

インデックスの文字列

let index = str.index(str.startIndex, offsetBy: 3)
String(str[index])    // "S"

サブストリング

let startIndex = str.index(str.startIndex, offsetBy: 3)
let endIndex = str.index(str.startIndex, offsetBy: 7)
String(str[startIndex...endIndex])     // "Strin"

最初のn文字

let startIndex = str.index(str.startIndex, offsetBy: 3)
String(str[..<startIndex])    // "My "

最後のn文字

let startIndex = str.index(str.startIndex, offsetBy: 3)
String(str[startIndex...])    // "String"

スイフト2と3

str = "My String"

**インデックスの文字列**

スイフト2

let charAtIndex = String(str[str.startIndex.advancedBy(3)])  // charAtIndex = "S"

スイフト3

str[str.index(str.startIndex, offsetBy: 3)]

SubString fromIndex toIndex

スイフト2

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

スイフト3

str[str.index(str.startIndex, offsetBy: 3)...str.index(str.startIndex, offsetBy: 7)]

最初のn文字

let first2Chars = String(str.characters.prefix(2)) // first2Chars = "My"

最後のn文字

let last3Chars = String(str.characters.suffix(3)) // last3Chars = "ing"
56

Xcode 7以降のSwift 2.0 GM Seed

var text = "Hello, world!"

let firstChar = text[text.startIndex.advancedBy(0)] // "H"

N番目の文字の場合は、0をn-1に置き換えます。

編集:Swift 3.0

text[text.index(text.startIndex, offsetBy: 0)]


[...] n.b。文字列内の特定の文字をつかむためのより簡単な方法があります。

例えばlet firstChar = text.characters.first

24
Matt Le Fleur

Cannot subscript a value of type 'String'...が表示されたらこの拡張子を使用してください。

スイフト3

extension String {
    subscript (i: Int) -> Character {
        return self[self.characters.index(self.startIndex, offsetBy: i)]
    }

    subscript (i: Int) -> String {
        return String(self[i] as Character)
    }

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

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

スイフト2.3

extension String {
    subscript(integerIndex: Int) -> Character {
        let index = advance(startIndex, integerIndex)
        return self[index]
    }

    subscript(integerRange: Range<Int>) -> String {
        let start = advance(startIndex, integerRange.startIndex)
        let end = advance(startIndex, integerRange.endIndex)
        let range = start..<end
        return self[range]
    }
}

ソース: http://oleb.net/blog/2014/07/Swift-strings/ /

23
SoftDesigner

Swift 2.2ソリューション:

次の拡張子はXcode 7で動作します。これは this ソリューションとSwift 2.0の構文変換の組み合わせです。

extension String {
    subscript(integerIndex: Int) -> Character {
        let index = startIndex.advancedBy(integerIndex)
        return self[index]
    }

    subscript(integerRange: Range<Int>) -> String {
        let start = startIndex.advancedBy(integerRange.startIndex)
        let end = startIndex.advancedBy(integerRange.endIndex)
        let range = start..<end
        return self[range]
    }
}
19
Dan Beaulieu

余談ですが、次のように、文字列の文字チェーン表現に直接適用できる関数がいくつかあります。

var string = "Hello, playground"
let firstCharacter = string.characters.first // returns "H"
let lastCharacter = string.characters.last // returns "d"

結果はCharacter型ですが、Stringにキャストすることもできます。

またはこれ:

let reversedString = String(string.characters.reverse())
// returns "dnuorgyalp ,olleH" 

:-)

11
Frédéric Adda

Swift文字列クラスは、UTF文字をネイティブにサポートしているため、特定のインデックスで文字を取得する機能を提供しません。メモリ内の可変長のUTF文字は、文字への直接ジャンプを不可能にします。つまり、毎回文字列を手動でループする必要があります。

文字列を拡張して、目的のインデックスまで文字をループするメソッドを提供できます。

extension String {
    func characterAtIndex(index: Int) -> Character? {
        var cur = 0
        for char in self {
            if cur == index {
                return char
            }
            cur++
        }
        return nil
    }
}

myString.characterAtIndex(0)!
11
drewag

スイフト4

String(Array(stringToIndex)[index]) 

これはおそらくこの問題を一度だけ解決するための最良の方法です。おそらく最初にStringを配列としてキャストし、次に結果をStringとして再度キャストしたいと思うでしょう。そうでなければ、文字列の代わりに文字が返されます。

String(Array("HelloThere")[1])は文字列として "e"を返します。

(Array("HelloThere")[1]はCharacterとして "e"を返します。

Swiftでは、文字列を配列のようにインデックス付けすることはできませんが、これで作業が完了します。

10
Harsh G.

私はちょうど同じ問題を抱えていました。単にこれを行います。

var aString: String = "test"
var aChar:unichar = (aString as NSString).characterAtIndex(0)
5
user3723247

私の非常に簡単な解決策:

let myString = "Test string"
let index = 0
let firstCharacter = myString[String.Index(encodedOffset: index)]
3
Linh Dao

Swift3

添字構文を使用して、特定の文字列インデックスの文字にアクセスできます。

let greeting = "Guten Tag!"
let index = greeting.index(greeting.startIndex, offsetBy: 7)
greeting[index] // a

https://developer.Apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/StringsAndCharacters.html にアクセスしてください。

または Swift 4 で文字列拡張を実行できます。

extension String {
    func getCharAtIndex(_ index: Int) -> Character {
        return self[self.index(self.startIndex, offsetBy: index)]
    }
}

使用法:

let foo = "ABC123"
foo.getCharAtIndex(2) //C
3
Hamed Akhlaghi

Swift 3: /別の解決策(遊び場でテスト済み)

extension String {
    func substr(_ start:Int, length:Int=0) -> String? {
        guard start > -1 else {
            return nil
        }

        let count = self.characters.count - 1

        guard start <= count else {
            return nil
        }

        let startOffset = max(0, start)
        let endOffset = length > 0 ? min(count, startOffset + length - 1) : count

        return self[self.index(self.startIndex, offsetBy: startOffset)...self.index(self.startIndex, offsetBy: endOffset)]
    }
}

使用法:

let txt = "12345"

txt.substr(-1) //nil
txt.substr(0) //"12345"
txt.substr(0, length: 0) //"12345"
txt.substr(1) //"2345"
txt.substr(2) //"345"
txt.substr(3) //"45"
txt.substr(4) //"5"
txt.substr(6) //nil
txt.substr(0, length: 1) //"1"
txt.substr(1, length: 1) //"2"
txt.substr(2, length: 1) //"3"
txt.substr(3, length: 1) //"4"
txt.substr(3, length: 2) //"45"
txt.substr(3, length: 3) //"45"
txt.substr(4, length: 1) //"5"
txt.substr(4, length: 2) //"5"
txt.substr(5, length: 1) //nil
txt.substr(5, length: -1) //nil
txt.substr(-1, length: -1) //nil
3
Peter Kreinz

私の解決策は、cadenaが文字列で4があなたが望むn番目の位置であると仮定して、一行にあります:

let character = cadena[advance(cadena.startIndex, 4)]

Simple ... Swiftには、将来のバージョンで部分文字列に関するより多くのことが含まれると思います。

スイフト4

Stringindicesプロパティを使用した範囲および部分範囲の添え字付け

@ LeoDabus Nice answer のバリエーションとして、 DefaultBidirectionalIndices に追加の拡張子を追加して、 indicesのカスタム添え字を実装するときのString のプロパティ(Intの特殊な範囲と部分的な範囲)の後者。

extension DefaultBidirectionalIndices {
    subscript(at: Int) -> Elements.Index {
        return index(startIndex, offsetBy: at)
    }
}

// Moving the index(_:offsetBy:) to an extension yields slightly
// briefer implementations for these String extensions.
extension String {
    subscript(r: CountableClosedRange<Int>) -> SubSequence {
        return self[indices[r.lowerBound]...indices[r.upperBound]]
    }
    subscript(r: CountablePartialRangeFrom<Int>) -> SubSequence {
        return self[indices[r.lowerBound]...]
    }
    subscript(r: PartialRangeThrough<Int>) -> SubSequence {
        return self[...indices[r.upperBound]]
    }
    subscript(r: PartialRangeUpTo<Int>) -> SubSequence {
        return self[..<indices[r.upperBound]]
    }
}

let str = "foo bar baz bax"
print(str[4...6]) // "bar"
print(str[4...])  // "bar baz bax"
print(str[...6])  // "foo bar"
print(str[..<6])  // "foo ba"

indices添え字に代わる(他の)代替としてStringプロパティを使用する方向を教えてくれて、@ LeoDabusに感謝します!

スウィフト4.2。

Swift 4.2では、 DefaultBidirectionalIndices が廃止され、 DefaultIndices が採用されました。

2
dfri

添字の取得と設定(文字列とサブストリング) - Swift 4.2

Swift 4.2、Xcode 10

私は @ alecarlson の答えに基づいて答えを決めました。唯一の大きな違いはですSubstringまたはStringが返されます(場合によっては単一のCharacter)。 添え字をgetおよびsetにすることもできます。最後に、私のものは @ alecarlson の答えよりも少し面倒で長くなります。そのため、ソースファイルに入れることをお勧めします。


拡張:

public extension String {
    public subscript (i: Int) -> Character {
        get {
            return self[index(startIndex, offsetBy: i)]
        }
        set (c) {
            let n = index(startIndex, offsetBy: i)
            replaceSubrange(n...n, with: "\(c)")
        }
    }
    public subscript (bounds: CountableRange<Int>) -> Substring {
        get {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(startIndex, offsetBy: bounds.upperBound)
            return self[start ..< end]
        }
        set (s) {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(startIndex, offsetBy: bounds.upperBound)
            replaceSubrange(start ..< end, with: s)
        }
    }
    public subscript (bounds: CountableClosedRange<Int>) -> Substring {
        get {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(startIndex, offsetBy: bounds.upperBound)
            return self[start ... end]
        }
        set (s) {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(startIndex, offsetBy: bounds.upperBound)
            replaceSubrange(start ... end, with: s)
        }

    }
    public subscript (bounds: CountablePartialRangeFrom<Int>) -> Substring {
        get {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(endIndex, offsetBy: -1)
            return self[start ... end]
        }
        set (s) {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(endIndex, offsetBy: -1)
            replaceSubrange(start ... end, with: s)
        }
    }
    public subscript (bounds: PartialRangeThrough<Int>) -> Substring {
        get {
            let end = index(startIndex, offsetBy: bounds.upperBound)
            return self[startIndex ... end]
        }
        set (s) {
            let end = index(startIndex, offsetBy: bounds.upperBound)
            replaceSubrange(startIndex ... end, with: s)
        }
    }
    public subscript (bounds: PartialRangeUpTo<Int>) -> Substring {
        get {
            let end = index(startIndex, offsetBy: bounds.upperBound)
            return self[startIndex ..< end]
        }
        set (s) {
            let end = index(startIndex, offsetBy: bounds.upperBound)
            replaceSubrange(startIndex ..< end, with: s)
        }
    }

    public subscript (i: Int) -> String {
        get {
            return "\(self[index(startIndex, offsetBy: i)])"
        }
        set (c) {
            let n = index(startIndex, offsetBy: i)
            self.replaceSubrange(n...n, with: "\(c)")
        }
    }
    public subscript (bounds: CountableRange<Int>) -> String {
        get {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(startIndex, offsetBy: bounds.upperBound)
            return "\(self[start ..< end])"
        }
        set (s) {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(startIndex, offsetBy: bounds.upperBound)
            replaceSubrange(start ..< end, with: s)
        }
    }
    public subscript (bounds: CountableClosedRange<Int>) -> String {
        get {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(startIndex, offsetBy: bounds.upperBound)
            return "\(self[start ... end])"
        }
        set (s) {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(startIndex, offsetBy: bounds.upperBound)
            replaceSubrange(start ... end, with: s)
        }

    }
    public subscript (bounds: CountablePartialRangeFrom<Int>) -> String {
        get {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(endIndex, offsetBy: -1)
            return "\(self[start ... end])"
        }
        set (s) {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(endIndex, offsetBy: -1)
            replaceSubrange(start ... end, with: s)
        }
    }
    public subscript (bounds: PartialRangeThrough<Int>) -> String {
        get {
            let end = index(startIndex, offsetBy: bounds.upperBound)
            return "\(self[startIndex ... end])"
        }
        set (s) {
            let end = index(startIndex, offsetBy: bounds.upperBound)
            replaceSubrange(startIndex ... end, with: s)
        }
    }
    public subscript (bounds: PartialRangeUpTo<Int>) -> String {
        get {
            let end = index(startIndex, offsetBy: bounds.upperBound)
            return "\(self[startIndex ..< end])"
        }
        set (s) {
            let end = index(startIndex, offsetBy: bounds.upperBound)
            replaceSubrange(startIndex ..< end, with: s)
        }
    }

    public subscript (i: Int) -> Substring {
        get {
            return Substring("\(self[index(startIndex, offsetBy: i)])")
        }
        set (c) {
            let n = index(startIndex, offsetBy: i)
            replaceSubrange(n...n, with: "\(c)")
        }
    }
}
public extension Substring {
    public subscript (i: Int) -> Character {
        get {
            return self[index(startIndex, offsetBy: i)]
        }
        set (c) {
            let n = index(startIndex, offsetBy: i)
            replaceSubrange(n...n, with: "\(c)")
        }

    }
    public subscript (bounds: CountableRange<Int>) -> Substring {
        get {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(startIndex, offsetBy: bounds.upperBound)
            return self[start ..< end]
        }
        set (s) {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(startIndex, offsetBy: bounds.upperBound)
            replaceSubrange(start ..< end, with: s)
        }
    }
    public subscript (bounds: CountableClosedRange<Int>) -> Substring {
        get {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(startIndex, offsetBy: bounds.upperBound)
            return self[start ... end]
        }
        set (s) {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(startIndex, offsetBy: bounds.upperBound)
            replaceSubrange(start ... end, with: s)
        }
    }
    public subscript (bounds: CountablePartialRangeFrom<Int>) -> Substring {
        get {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(endIndex, offsetBy: -1)
            return self[start ... end]
        }
        set (s) {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(endIndex, offsetBy: -1)
            replaceSubrange(start ... end, with: s)
        }

    }
    public subscript (bounds: PartialRangeThrough<Int>) -> Substring {
        get {
            let end = index(startIndex, offsetBy: bounds.upperBound)
            return self[startIndex ... end]
        }
        set (s) {
            let end = index(startIndex, offsetBy: bounds.upperBound)
            replaceSubrange(startIndex ..< end, with: s)
        }
    }
    public subscript (bounds: PartialRangeUpTo<Int>) -> Substring {
        get {
            let end = index(startIndex, offsetBy: bounds.upperBound)
            return self[startIndex ..< end]
        }
        set (s) {
            let end = index(startIndex, offsetBy: bounds.upperBound)
            replaceSubrange(startIndex ..< end, with: s)
        }
    }
    public subscript (i: Int) -> String {
        get {
            return "\(self[index(startIndex, offsetBy: i)])"
        }
        set (c) {
            let n = index(startIndex, offsetBy: i)
            replaceSubrange(n...n, with: "\(c)")
        }
    }
    public subscript (bounds: CountableRange<Int>) -> String {
        get {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(startIndex, offsetBy: bounds.upperBound)
            return "\(self[start ..< end])"
        }
        set (s) {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(startIndex, offsetBy: bounds.upperBound)
            replaceSubrange(start ..< end, with: s)
        }
    }
    public subscript (bounds: CountableClosedRange<Int>) -> String {
        get {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(startIndex, offsetBy: bounds.upperBound)
            return "\(self[start ... end])"
        }
        set (s) {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(startIndex, offsetBy: bounds.upperBound)
            replaceSubrange(start ... end, with: s)
        }

    }
    public subscript (bounds: CountablePartialRangeFrom<Int>) -> String {
        get {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(endIndex, offsetBy: -1)
            return "\(self[start ... end])"
        }
        set (s) {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(endIndex, offsetBy: -1)
            replaceSubrange(start ... end, with: s)
        }
    }
    public subscript (bounds: PartialRangeThrough<Int>) -> String {
        get {
            let end = index(startIndex, offsetBy: bounds.upperBound)
            return "\(self[startIndex ... end])"
        }
        set (s) {
            let end = index(startIndex, offsetBy: bounds.upperBound)
            replaceSubrange(startIndex ... end, with: s)
        }
    }
    public subscript (bounds: PartialRangeUpTo<Int>) -> String {
        get {
            let end = index(startIndex, offsetBy: bounds.upperBound)
            return "\(self[startIndex ..< end])"
        }
        set (s) {
            let end = index(startIndex, offsetBy: bounds.upperBound)
            replaceSubrange(startIndex ..< end, with: s)
        }
    }

    public subscript (i: Int) -> Substring {
        get {
            return Substring("\(self[index(startIndex, offsetBy: i)])")
        }
        set (c) {
            let n = index(startIndex, offsetBy: i)
            replaceSubrange(n...n, with: "\(c)")
        }
    }
}
2
Noah Wilder

件名をフィードしてSwiftの添え字の可能性を示すために、これは小さな文字列 "substring-toolbox"の添え字ベースです。

これらのメソッドは安全であり、文字列インデックスを超えることはありません

extension String {
    // string[i] -> one string char
    subscript(pos: Int) -> String { return String(Array(self)[min(self.length-1,max(0,pos))]) }

    // string[pos,len] -> substring from pos for len chars on the left
    subscript(pos: Int, len: Int) -> String { return self[pos, len, .pos_len, .left2right] }

    // string[pos, len, .right2left] -> substring from pos for len chars on the right
    subscript(pos: Int, len: Int, way: Way) -> String { return self[pos, len, .pos_len, way] }

    // string[range] -> substring form start pos on the left to end pos on the right
    subscript(range: Range<Int>) -> String { return self[range.startIndex, range.endIndex, .start_end, .left2right] }

    // string[range, .right2left] -> substring start pos on the right to end pos on the left
    subscript(range: Range<Int>, way: Way) -> String { return self[range.startIndex, range.endIndex, .start_end, way] }

    var length: Int { return countElements(self) }
    enum Mode { case pos_len, start_end }
    enum Way { case left2right, right2left }
    subscript(var val1: Int, var val2: Int, mode: Mode, way: Way) -> String {
        if mode == .start_end {
            if val1 > val2 { let val=val1 ; val1=val2 ; val2=val }
            val2 = val2-val1
        }
        if way == .left2right {
            val1 = min(self.length-1, max(0,val1))
            val2 = min(self.length-val1, max(1,val2))
        } else {
            let val1_ = val1
            val1 = min(self.length-1, max(0, self.length-val1_-val2 ))
            val2 = max(1, (self.length-1-val1_)-(val1-1) )
        }
        return self.bridgeToObjectiveC().substringWithRange(NSMakeRange(val1, val2))

        //-- Alternative code without bridge --
        //var range: Range<Int> = pos...(pos+len-1)
        //var start = advance(startIndex, range.startIndex)
        //var end = advance(startIndex, range.endIndex)
        //return self.substringWithRange(Range(start: start, end: end))
    }
}


println("0123456789"[3]) // return "3"

println("0123456789"[3,2]) // return "34"

println("0123456789"[3,2,.right2left]) // return "56"

println("0123456789"[5,10,.pos_len,.left2right]) // return "56789"

println("0123456789"[8,120,.pos_len,.right2left]) // return "01"

println("0123456789"[120,120,.pos_len,.left2right]) // return "9"

println("0123456789"[0...4]) // return "01234"

println("0123456789"[0..4]) // return "0123"

println("0123456789"[0...4,.right2left]) // return "56789"

println("0123456789"[4...0,.right2left]) // return "678" << because ??? range can wear endIndex at 0 ???
2
Luc-Olivier

スイフト4.2

この答えは理想的です。なぜならそれはStringとそのすべてのSubsequencesSubstring)を一つの拡張子に拡張するからです。

public extension StringProtocol {

    public subscript (i: Int) -> Element {
        return self[index(startIndex, offsetBy: i)]
    }

    public subscript (bounds: CountableClosedRange<Int>) -> SubSequence {
        let start = index(startIndex, offsetBy: bounds.lowerBound)
        let end = index(startIndex, offsetBy: bounds.upperBound)
        return self[start...end]
    }

    public subscript (bounds: CountableRange<Int>) -> SubSequence {
        let start = index(startIndex, offsetBy: bounds.lowerBound)
        let end = index(startIndex, offsetBy: bounds.upperBound)
        return self[start..<end]
    }

    public subscript (bounds: PartialRangeUpTo<Int>) -> SubSequence {
        let end = index(startIndex, offsetBy: bounds.upperBound)
        return self[startIndex..<end]
    }

    public subscript (bounds: PartialRangeThrough<Int>) -> SubSequence {
        let end = index(startIndex, offsetBy: bounds.upperBound)
        return self[startIndex...end]
    }

    public subscript (bounds: CountablePartialRangeFrom<Int>) -> SubSequence {
        let start = index(startIndex, offsetBy: bounds.lowerBound)
        return self[start..<endIndex]
    }
}

使用法

var str = "Hello, playground"

print(str[5...][...5][0])
// Prints ","
2
Noah Wilder

Swift 2.0 subString用のアップデート

public extension String {
    public subscript (i: Int) -> String {
        return self.substringWithRange(self.startIndex..<self.startIndex.advancedBy(i + 1))
    }

    public subscript (r: Range<Int>) -> String {
        get {
            return self.substringWithRange(self.startIndex.advancedBy(r.startIndex)..<self.startIndex.advancedBy(r.endIndex))
        }
    }

}
2
YannSteph

Swift 3では

    let mystring = "Hello, world!"
    let stringToArray = Array(mystring.characters)

    let indices = (stringToArray.count)-1

    print(stringToArray[0]) //H
    print(stringToArray[indices]) //!
2
Rajamohan S

スイフト3

extension String {

    public func charAt(_ i: Int) -> Character {
        return self[self.characters.index(self.startIndex, offsetBy: i)]
    }

    public subscript (i: Int) -> String {
        return String(self.charAt(i) as Character)
    }

    public subscript (r: Range<Int>) -> String {
        return substring(with: self.characters.index(self.startIndex, offsetBy: r.lowerBound)..<self.characters.index(self.startIndex, offsetBy: r.upperBound))
    }

    public subscript (r: CountableClosedRange<Int>) -> String {
        return substring(with: self.characters.index(self.startIndex, offsetBy: r.lowerBound)..<self.characters.index(self.startIndex, offsetBy: r.upperBound))
    }

}

使用方法

let str = "Hello World"
let sub = str[0...4]

役に立つプログラミングのヒントとコツ(私が書いた)

2
quemeful

私は最初のキャラクターを手に入れるための素早い答えは次のようになると思います。

let firstCharacter = aString[aString.startIndex]

それは以下よりもとてもエレガントでパフォーマンスが高いです。

let firstCharacter = Array(aString.characters).first

しかし、文字列を操作してさらに操作をしたい場合は、拡張機能を作成することを検討してください。このアプローチの拡張機能の1つは、すでにここに掲載されているものとよく似ています。

extension String {
var length : Int {
    return self.characters.count
}

subscript(integerIndex: Int) -> Character {
    let index = startIndex.advancedBy(integerIndex)
    return self[index]
}

subscript(integerRange: Range<Int>) -> String {
    let start = startIndex.advancedBy(integerRange.startIndex)
    let end = startIndex.advancedBy(integerRange.endIndex)
    let range = start..<end
    return self[range]
}

}

しかしそれは素晴らしいアイデアです!

下記の拡張は非常に非効率的です。文字列が整数でアクセスされるたびに、開始インデックスを進めるためのO(n)関数が実行されます。別の線形ループの内側で線形ループを実行すると、このforループが誤ってO(n2)となります。文字列の長さが増えると、このループにかかる時間は2次的に増えます。

その代わりに、文字の文字列コレクションを使用できます。

2
ignaciohugog

Stringをそのような文字の配列に変換することもできます。

let text = "My Text"
let index = 2
let charSequence = text.unicodeScalars.map{ Character($0) }
let char = charSequence[index]

これは、指定したインデックスのcharを一定時間で取得する方法です。

以下の例は一定時間では実行されませんが、線形時間を必要とします。そのため、インデックスで文字列を検索することが多い場合は、上記の方法を使用します。

let char = text[text.startIndex.advancedBy(index)]
1
Marcin Kapusta

SwiftのString型は、Unicode文字列をエンコードできる方法がいくつかあるため、characterAtIndexメソッドを提供しません。あなたはUTF8、UTF16、または他の何かで行きますか?

String.utf8およびString.utf16プロパティを取得することでCodeUnitコレクションにアクセスできます。 String.unicodeScalarsプロパティを取得してUnicodeScalarコレクションにアクセスすることもできます。

NSStringの実装の精神で、私はunichar型を返しています。

extension String
{
    func characterAtIndex(index:Int) -> unichar
    {
        return self.utf16[index]
    }

    // Allows us to use String[index] notation
    subscript(index:Int) -> unichar
    {
        return characterAtIndex(index)
    }
}

let text = "Hello Swift!"
let firstChar = text[0]
1
Erik

Swift 3では、Stringクラスを拡張せずに、簡単に作成できます。

let myString = "abcedfg"
let characterLocationIndex = myString.index(myString.startIndex, offsetBy: 3)
let myCharacter = myString[characterLocationIndex]

この例では、myCharacterは「3」です。

1
John Pavley

文字 を使用して作業を行います。 String をCharacterViewメソッドで操作できる文字の配列に簡単に変換できます。

例:

let myString = "Hello World!"
let myChars  = myString.characters

(full CharacterView doc)

(Swift 3でテスト済み)

1
Stephane Paquet

最初の文字を取得します。

first(str) // retrieve first letter

もっとここに: http://sketchytech.blogspot.com/2014/08/Swift-pure-Swift-method-for-returning.html

1
philippinedev

で説明されている代替方法があります /文字列マニフェスト - /

extension String : BidirectionalCollection {
    subscript(i: Index) -> Character { return characters[i] }
}
1

あなたは負のインデックスを使用することができますpythonのようなソリューション、

var str = "Hello world!"
str[-1]        // "!"

になり得る:

extension String {
    subscript (var index:Int)->Character{
        get {
            let n = distance(self.startIndex, self.endIndex)
            index %= n
            if index < 0 { index += n }
            return self[advance(startIndex, index)]
        }
    }
}

ところで、 pythonのスライス表記全体を置き換えたほうが価値があるかもしれません

1

これがSwift 3.1で動作するあなたが使用できる拡張です。単一のインデックスはCharacterを返します。これはStringをインデックスするときに直感的に思えます。そしてRangeStringを返します。

extension String {
    subscript (i: Int) -> Character {
        return Array(self.characters)[i]
    }

    subscript (r: CountableClosedRange<Int>) -> String {
        return String(Array(self.characters)[r])
    }

    subscript (r: CountableRange<Int>) -> String {
        return self[r.lowerBound...r.upperBound-1]
    }
}

実際の拡張のいくつかの例:

let string = "Hello"

let c1 = string[1]  // Character "e"
let c2 = string[-1] // fatal error: Index out of range

let r1 = string[1..<4] // String "ell"
let r2 = string[1...4] // String "Ello"
let r3 = string[1...5] // fatal error: Array index is out of range



n.b上記の拡張子に追加のメソッドを追加して、必要に応じて1文字のStringを返すことができます。

subscript (i: Int) -> String {
    return String(self[i])
}

その場合は、文字列のインデックス作成時に必要な型を明示的に指定する必要があります。

let c: Character = string[3] // Character "l"
let s: String = string[0]    // String "H"
1
Matt Le Fleur

これはSwift 4です。

let myString = "LOVE"

self.textField1.text = String(Array(myString)[0])
self.textField2.text = String(Array(myString)[1])
self.textField3.text = String(Array(myString)[2])
self.textField4.text = String(Array(myString)[3])
0
Sreekanth G

負の指数を許可します

添字拡張子を使用するとき、最後の文字を取得するためにstring[string.length - 1]を書く必要が常にあるとは限らないので、常に便利です。この( Swift 3 )拡張は負のインデックス、RangeおよびCountableClosedRangeを可能にします。

extension String {
    var count: Int { return self.characters.count }

    subscript (i: Int) -> Character {
        // wraps out of bounds indices
        let j = i % self.count
        // wraps negative indices
        let x = j < 0 ? j + self.count : j

        // quick exit for first
        guard x != 0 else {
            return self.characters.first!
        }

        // quick exit for last
        guard x != count - 1 else {
            return self.characters.last!
        }

        return self[self.index(self.startIndex, offsetBy: x)]
    }

    subscript (r: Range<Int>) -> String {
        let lb = r.lowerBound
        let ub = r.upperBound

        // quick exit for one character
        guard lb != ub else { return String(self[lb]) }

        return self[self.index(self.startIndex, offsetBy: lb)..<self.index(self.startIndex, offsetBy: ub)]
    }

    subscript (r: CountableClosedRange<Int>) -> String {
        return self[r.lowerBound..<r.upperBound + 1]
    }
}

使い方は?

var text = "Hello World"

text[-1]    // d
text[2]     // l
text[12]    // e
text[0...4] // Hello
text[0..<4] // Hell

より徹底的なプログラマーのために:この拡張に空の文字列に対するguardを含める

subscript (i: Int) -> Character {
    guard self.count != 0 else { return '' }
    ...
}

subscript (r: Range<Int>) -> String {
    guard self.count != 0 else { return "" }
    ...
}
0
Jay Harris

この拡張子をプロジェクトに含めます

  extension String{
func trim() -> String
{
    return self.trimmingCharacters(in: NSCharacterSet.whitespaces)
}

var length: Int {
    return self.count
}

subscript (i: Int) -> String {
    return self[i ..< i + 1]
}

func substring(fromIndex: Int) -> String {
    return self[min(fromIndex, length) ..< length]
}

func substring(toIndex: Int) -> String {
    return self[0 ..< max(0, toIndex)]
}

subscript (r: Range<Int>) -> String {
    let range = Range(uncheckedBounds: (lower: max(0, min(length, r.lowerBound)),
                                        upper: min(length, max(0, r.upperBound))))
    let start = index(startIndex, offsetBy: range.lowerBound)
    let end = index(start, offsetBy: range.upperBound - range.lowerBound)
    return String(self[start ..< end])
}

func substring(fromIndex: Int, toIndex:Int)->String{
    let startIndex = self.index(self.startIndex, offsetBy: fromIndex)
    let endIndex = self.index(startIndex, offsetBy: toIndex-fromIndex)

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

その後、このような機能を使用する

let str = "Sample-String"

let substring = str.substring(fromIndex: 0, toIndex: 0) //returns S
let sampleSubstr = str.substring(fromIndex: 0, toIndex: 5) //returns Sample
0
AkilRajdho

スイフト3:

extension String {
    func substring(fromPosition: UInt, toPosition: UInt) -> String? {
        guard fromPosition <= toPosition else {
            return nil
        }

        guard toPosition < UInt(characters.count) else {
            return nil
        }

        let start = index(startIndex, offsetBy: String.IndexDistance(fromPosition))
        let end   = index(startIndex, offsetBy: String.IndexDistance(toPosition) + 1)
        let range = start..<end

        return substring(with: range)
    }
}

"ffaabbcc".substring(fromPosition: 2, toPosition: 5) // return "aabb"
0
Daniele Ceglia

これを行うにはSwiftString( https://github.com/amayne/SwiftString )を使用できます。

"Hello, world!"[0] // H
"Hello, world!"[0...4] // Hello

免責事項:私はこの拡張子を書いた

0
eurobrew

大きな文字列があり、そこから多数の文字にランダムにアクセスする必要がある場合は、パフォーマンスを向上させるために追加のメモリコストを払い、文字列を配列に変換することをお勧めします。

// Pay up front for O(N) memory
let chars = Array(veryLargeString.characters)

for i in 0...veryLargeNumber {
    // Benefit from O(1) access
    print(chars[i])
}
0
Joseph Chen