文字列のn番目の文字を取得する方法私は幸運にもブラケット([]
)アクセサを試してみました。
var string = "Hello, world!"
var firstChar = string[0] // Throws error
エラー: '添え字'は利用できません:文字列にIntを添え字で付けることはできません。
注意: Swift 4の適切な実装については Leo Dabusの答え をご覧ください。
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]
}
}
Substring
をString
に変換するために、あなたは単にString(string[0..2])
をすることができます、しかし、あなたが周りの部分文字列を維持することを計画する場合にだけそうするべきです。そうでなければ、それをSubstring
にしたほうが効率的です。
誰かがこれら2つの拡張を1つにマージするための良い方法を見つけ出すことができれば素晴らしいでしょう。 StringProtocol
メソッドが存在しないため、index
を無理に拡張しようとしました。
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.localizedLowercaseString
、String.localizedStandardRangeOfString()
など、ロケールに応じた高レベルのUnicodeアルゴリズムを使用してください。
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"
私はちょうどこのきちんとした回避策を思い付きました
var firstChar = Array(string)[0]
整数を使用した索引付けは行わず、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]
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 ????????!!!"
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"
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"
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
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]
}
}
次の拡張子は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]
}
}
余談ですが、次のように、文字列の文字チェーン表現に直接適用できる関数がいくつかあります。
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"
:-)
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)!
スイフト4
String(Array(stringToIndex)[index])
これはおそらくこの問題を一度だけ解決するための最良の方法です。おそらく最初にStringを配列としてキャストし、次に結果をStringとして再度キャストしたいと思うでしょう。そうでなければ、文字列の代わりに文字が返されます。
例String(Array("HelloThere")[1])
は文字列として "e"を返します。
(Array("HelloThere")[1]
はCharacterとして "e"を返します。
Swiftでは、文字列を配列のようにインデックス付けすることはできませんが、これで作業が完了します。
私はちょうど同じ問題を抱えていました。単にこれを行います。
var aString: String = "test"
var aChar:unichar = (aString as NSString).characterAtIndex(0)
私の非常に簡単な解決策:
let myString = "Test string"
let index = 0
let firstCharacter = myString[String.Index(encodedOffset: index)]
Swift3
添字構文を使用して、特定の文字列インデックスの文字にアクセスできます。
let greeting = "Guten Tag!"
let index = greeting.index(greeting.startIndex, offsetBy: 7)
greeting[index] // a
または Swift 4 で文字列拡張を実行できます。
extension String {
func getCharAtIndex(_ index: Int) -> Character {
return self[self.index(self.startIndex, offsetBy: index)]
}
}
使用法:
let foo = "ABC123"
foo.getCharAtIndex(2) //C
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
私の解決策は、cadenaが文字列で4があなたが望むn番目の位置であると仮定して、一行にあります:
let character = cadena[advance(cadena.startIndex, 4)]
Simple ... Swiftには、将来のバージョンで部分文字列に関するより多くのことが含まれると思います。
String
のindices
プロパティを使用した範囲および部分範囲の添え字付け@ 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に感謝します!
Swift 4.2では、 DefaultBidirectionalIndices
が廃止され、 DefaultIndices
が採用されました。
私は @ 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)")
}
}
}
件名をフィードして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 ???
この答えは理想的です。なぜならそれはString
とそのすべてのSubsequences
(Substring
)を一つの拡張子に拡張するからです。
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 ","
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))
}
}
}
Swift 3では
let mystring = "Hello, world!"
let stringToArray = Array(mystring.characters)
let indices = (stringToArray.count)-1
print(stringToArray[0]) //H
print(stringToArray[indices]) //!
スイフト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]
私は最初のキャラクターを手に入れるための素早い答えは次のようになると思います。
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次的に増えます。
その代わりに、文字の文字列コレクションを使用できます。
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)]
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]
Swift 3では、Stringクラスを拡張せずに、簡単に作成できます。
let myString = "abcedfg"
let characterLocationIndex = myString.index(myString.startIndex, offsetBy: 3)
let myCharacter = myString[characterLocationIndex]
この例では、myCharacterは「3」です。
文字 を使用して作業を行います。 String をCharacterViewメソッドで操作できる文字の配列に簡単に変換できます。
例:
let myString = "Hello World!"
let myChars = myString.characters
(full CharacterView doc)
(Swift 3でテスト済み)
最初の文字を取得します。
first(str) // retrieve first letter
もっとここに: http://sketchytech.blogspot.com/2014/08/Swift-pure-Swift-method-for-returning.html
で説明されている代替方法があります /文字列マニフェスト - /
extension String : BidirectionalCollection {
subscript(i: Index) -> Character { return characters[i] }
}
あなたは負のインデックスを使用することができます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)]
}
}
}
これがSwift 3.1で動作するあなたが使用できる拡張です。単一のインデックスはCharacter
を返します。これはString
をインデックスするときに直感的に思えます。そしてRange
はString
を返します。
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"
これは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])
負の指数を許可します
添字拡張子を使用するとき、最後の文字を取得するために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 "" }
...
}
この拡張子をプロジェクトに含めます
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
スイフト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"
これを行うにはSwiftString( https://github.com/amayne/SwiftString )を使用できます。
"Hello, world!"[0] // H
"Hello, world!"[0...4] // Hello
免責事項:私はこの拡張子を書いた
大きな文字列があり、そこから多数の文字にランダムにアクセスする必要がある場合は、パフォーマンスを向上させるために追加のメモリコストを払い、文字列を配列に変換することをお勧めします。
// 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])
}