1. ホーム
  2. swift

[解決済み] SwiftでStringのサブストリングはどのように動作するか

2022-03-21 09:02:20

質問

私はSwift 3で私の古いコードと回答のいくつかを更新してきましたが、Swiftの文字列と部分文字列でのインデックスに到達したとき、物事は混乱しました。

具体的には以下のようなことを試していました。

let str = "Hello, playground"
let prefixRange = str.startIndex..<str.startIndex.advancedBy(5)
let prefix = str.substringWithRange(prefixRange)

ここで、2行目が次のようなエラーになっていました。

型 'String' の値には、メンバー 'substringWithRange' がありません。

なるほど String は、現在、以下のメソッドを持っています。

str.substring(to: String.Index)
str.substring(from: String.Index)
str.substring(with: Range<String.Index>)

これらは、最初本当に私を混乱させたので、私は遊び始めました。 インデックスとレンジ . これはsubstringの質問と回答の続きです。どのように使用されるかを示すために、以下に回答を追加しています。

どのように解決するのですか?

以下の例では、すべて

var str = "Hello, playground"

スウィフト4

Swift 4 では、文字列はかなり大きなオーバーホールを受けました。今、文字列からある部分文字列を取得するとき、あなたは Substring 型ではなく String . これはなぜでしょうか?文字列はSwiftの値型です。つまり、新しいものを作るために1つのStringを使用する場合、それはコピーオーバーされなければならないことを意味します。これは安定性のために良いですが(あなたの知識なしで他の誰もそれを変更するつもりはない)、効率のために悪いです。

一方、Substringは、元のStringを参照するものである。以下は ドキュメント を説明する。

コピーする必要がないので、より効率的に使用することができます。しかし、100万文字のStringから10文字のSubstringを取得したとします。SubstringはStringを参照しているので、Substringが存在する限り、システムはString全体を保持しなければならない。したがって、Substringの操作が終わったら、それをStringに変換してください。

let myString = String(mySubstring)

これは、部分文字列だけをコピーし、古い文字列を保持しているメモリは、次のようにすることができます。 回収 . サブストリングは(タイプとして)短命であることを意図しています。

Swift 4のもう一つの大きな改良点は、文字列が(再び)コレクションになったことです。それは、あなたがコレクションにできることは何でも、あなたが文字列にできることを意味します(添え字の使用、文字上の繰り返し、フィルタリングなど)。

次の例は、Swift で部分文字列を取得する方法を示しています。

部分文字列の取得

文字列から部分文字列を取得するには、添え字や他の多くの方法(例えば。 prefix , suffix , split ). この場合でも String.Index であり Int のインデックスを範囲指定しますが。(参照 もう一つの答え ということです)。

文字列の先頭

添え字を使用することができます(Swift 4の片側範囲に注意)。

let index = str.index(str.startIndex, offsetBy: 5)
let mySubstring = str[..<index] // Hello

または prefix :

let index = str.index(str.startIndex, offsetBy: 5)
let mySubstring = str.prefix(upTo: index) // Hello

またはもっと簡単です。

let mySubstring = str.prefix(5) // Hello

文字列の末尾

添え字を使う

let index = str.index(str.endIndex, offsetBy: -10)
let mySubstring = str[index...] // playground

または suffix :

let index = str.index(str.endIndex, offsetBy: -10)
let mySubstring = str.suffix(from: index) // playground

またはもっと簡単です。

let mySubstring = str.suffix(10) // playground

を使用する場合は注意してください。 suffix(from: index) を使うことで、最後からカウントバックする必要がありました。 -10 . を使用する場合、その必要はありません。 suffix(x) これは単に最後の x の文字が含まれます。

文字列内の範囲

ここでも単に添え字を使うだけです。

let start = str.index(str.startIndex, offsetBy: 7)
let end = str.index(str.endIndex, offsetBy: -6)
let range = start..<end

let mySubstring = str[range]  // play

変換する Substring から String

忘れてはならないのは、部分文字列を保存する準備ができたら、それを String そうすれば、古い文字列のメモリを掃除することができます。

let myString = String(mySubstring)

を使用しています。 Int インデックス拡張?

を使うのはためらわれる。 Int の記事を読んでから、インデックス拡張をベースにした Swift 3 の文字列 Airspeed VelocityとOle Begemannによるものです。Swift 4 では、文字列はコレクションですが、Swift チームは、意図的に、文字列を使用しないようにしました。 Int のインデックスを作成します。それは今でも String.Index . これは Swift Characters が様々な数の Unicode コードポイントから構成されていることと関係があります。実際のインデックスはすべての文字列に対して一意的に計算されなければなりません。

私は、Swiftチームが抽象化する方法を見つけることを望んでいると言わざるを得ません。 String.Index 将来的には でも、それまでは彼らのAPIを使うことにしています。Stringの操作は単純な Int のインデックス検索を行います。