Swiftで文字列から最初の文字を削除する最も簡単な方法は何ですか?


122

文字列から最初の文字を削除したい。これまでのところ、私が思いついた最も簡潔なことは:

display.text = display.text!.substringFromIndex(advance(display.text!.startIndex, 1))

IntUnicodeのために文字列にインデックスを付けることができないことはわかっていますが、このソリューションは非常に冗長に見えます。私が見落としている別の方法はありますか?


3
実際には、NSStringにadvanceキャストdisplay.text!することで全体を回避できます。それが良い解決策であると言っているのではありません-考えられる誤解を修正するだけです。NSStringを使用すると、Intでそれにインデックスを付けることができます。-そして、Intでインデックスを作成できないのは、Unicodeが原因ではありません。これは、キャラクターが複数の複合コードポイントで構成されている可能性があるためです。
マット2015

大文字を使用するためにこれを行う場合、StringSwift 3はにcapitalized関数を導入していますString
Vince O'Sullivan 2017年

回答:


207

Swift 3を使用している場合は、この回答の2番目のセクションを無視できます。朗報ですが、これは実際には再び簡潔になりました!Stringの新しいremove(at :)メソッドを使用するだけです。

var myString = "Hello, World"
myString.remove(at: myString.startIndex)

myString // "ello, World"

dropFirst()このためのグローバル関数が好きです。

let original = "Hello" // Hello
let sliced = dropFirst(original) // ello

これは短く、明確で、Sliceableプロトコルに準拠するすべてのもので機能します。

Swift 2を使用している場合、この答えは変わりました。それでもdropFirstを使用できますが、strings charactersプロパティから最初の文字を削除してから、結果をStringに変換し直す必要があります。dropFirstも関数ではなくメソッドになっています。

let original = "Hello" // Hello
let sliced = String(original.characters.dropFirst()) // ello

別の方法は、suffix関数を使用して文字列のを接合することUTF16Viewです。もちろん、これも後でStringに変換する必要があります。

let original = "Hello" // Hello
let sliced = String(suffix(original.utf16, original.utf16.count - 1)) // ello

これはすべて、私が最初に提供したソリューションが、Swiftの新しいバージョンでこれを行う最も簡単な方法ではないことが判明したということです。removeAtIndex()短くて直感的なソリューションを探している場合は、@ chrisのソリューションを使用することをお勧めします。

var original = "Hello" // Hello
let removedChar = original.removeAtIndex(original.startIndex)

original // ello

以下のコメントで@vacawamaによって指摘されているように、元の文字列を変更しない別のオプションは、substringFromIndexを使用することです。

let original = "Hello" // Hello
let substring = original.substringFromIndex(advance(original.startIndex, 1)) // ello

または、文字列の最初と最後から文字を削除しようとしている場合は、substringWithRangeを使用できます。ときに条件に注意してくださいstartIndex + n > endIndex - m

let original = "Hello" // Hello

let newStartIndex = advance(original.startIndex, 1)
let newEndIndex = advance(original.endIndex, -1)

let substring = original.substringWithRange(newStartIndex..<newEndIndex) // ell

最後の行は、添え字表記を使用して書くこともできます。

let substring = original[newStartIndex..<newEndIndex]

2
また、財団の世界に足を踏み入れる必要もありません。
マット2015

2
そして、それは非常に迅速/ fpです。
David Berry、

ありがとう、それははるかにエレガントです。私は長年Objective Cでプログラミングをしており、SwiftでiTunes U Stanford iOSプログラミングコースを受講しています。私はまだ新しいパラダイムについて学ぶことがたくさんあります。
SSteve 2015

1
dropLastまたはdropFirstを使用する際は、文字列のラップを解除しないと機能しないことに注意してください。
Bhavuk Jain

3
正解です。remove(at:)メソッドの戻り値に注目する価値があると思います。これは、新しい文字列ではなく、削除された文字です。たとえば、let removedCharacter = myString.remove(at: myString.startIndex)。私は、メソッド呼び出しの結果を返すのを間違えていました。これがこのアプローチの場合であることを忘れていました。すべてをコーディングしてください!
kbpontius

118

Swift 4のアップデート

Swift 4では再びString準拠しているCollectionため、文字列の最初と最後を使用dropFirstdropLastたりトリミングしたりすることが可能です。結果は型Substringであるため、を返すには、それをStringコンストラクタに渡す必要がありますString

let str = "hello"
let result1 = String(str.dropFirst())    // "ello"
let result2 = String(str.dropLast())     // "hell"

dropFirst()そして、dropLast()も取るIntドロップする文字数を指定するには:

let result3 = String(str.dropLast(3))    // "he"
let result4 = String(str.dropFirst(4))   // "o"

ドロップする文字を文字列より多く指定すると、結果は空の文字列("")になります。

let result5 = String(str.dropFirst(10))  // ""

Swift 3のアップデート

最初の文字を削除し、元の文字列を変更したい場合は、@ MickMacCallumの回答を参照してください。プロセスで新しい文字列を作成する場合は、を使用しますsubstring(from:)。拡張機能ではString、あなたがの醜さを隠すことができるsubstring(from:)substring(to:)の開始と終了をトリミングするために便利な追加を作成するにはString

extension String {
    func chopPrefix(_ count: Int = 1) -> String {
        return substring(from: index(startIndex, offsetBy: count))
    }

    func chopSuffix(_ count: Int = 1) -> String {
        return substring(to: index(endIndex, offsetBy: -count))
    }
}

"hello".chopPrefix()    // "ello"
"hello".chopPrefix(3)   // "lo"

"hello".chopSuffix()    // "hell"
"hello".chopSuffix(3)   // "he"

同様にdropFirstしてdropLast彼らの前に、これらの関数は、文字列で使用できる十分な文字が存在しない場合はクラッシュしてしまいます。責任は、それらを適切に使用するために呼び出し側にあります。これは有効な設計決定です。それらを作成して、呼び出し側でラップ解除する必要があるオプションを返すようにすることができます。


Swift 2.x

でああスウィフト2dropFirst及びdropLast(前の最善の解決策は)彼らが前にいたほど便利ではありません。の拡張により、and Stringの醜さを隠すことができます:substringFromIndexsubstringToIndex

extension String {
    func chopPrefix(count: Int = 1) -> String {
         return self.substringFromIndex(advance(self.startIndex, count))
    }

    func chopSuffix(count: Int = 1) -> String {
        return self.substringToIndex(advance(self.endIndex, -count))
    }
}

"hello".chopPrefix()    // "ello"
"hello".chopPrefix(3)   // "lo"

"hello".chopSuffix()    // "hell"
"hello".chopSuffix(3)   // "he"

同様にdropFirstしてdropLast彼らの前に、これらの関数は、文字列で使用できる十分な文字が存在しない場合はクラッシュしてしまいます。責任は、それらを適切に使用するために呼び出し側にあります。これは有効な設計決定です。それらを作成して、呼び出し側でラップ解除する必要があるオプションを返すようにすることができます。


スウィフト1.2、あなたが呼び出す必要がありますchopPrefix。このように:

"hello".chopPrefix(count: 3)  // "lo"

または_、関数定義にアンダースコアを追加して、パラメーター名を抑制できます。

extension String {
    func chopPrefix(_ count: Int = 1) -> String {
         return self.substringFromIndex(advance(self.startIndex, count))
    }

    func chopSuffix(_ count: Int = 1) -> String {
        return self.substringToIndex(advance(self.endIndex, -count))
    }
}

3
私はまだSwiftの組み込みの文字列操作がいかに複雑であるかに驚いています。これは基本的な、基本的なものです。パーサーを実装しているようには見えません。これを簡単にする拡張機能をありがとう。AppleがこれをStringクラスに追加するだけでは困るのは困惑です。多分それはまだ流動的です。
devios1 2016

これが彼らが「進化」した子供達と呼んでいるものです。私たちが毎日それに対処する必要がなければ、それは陽気です。String APIがこのようになっている理由はあると思いますが、本当に、これは、この言語に変換する可能性が非常に高くなるのを先延ばしにする必要があります。以前のコメンターは完全に正しいです-これは基本的な、基本的なものでなければなりません。
Quintin Willison、2017年

17

Swift 2.2

'advance'は使用できません:インデックスで 'advancedBy(n)'メソッドを呼び出します

    func chopPrefix(count: Int = 1) -> String {
        return self.substringFromIndex(self.startIndex.advancedBy(count))
    }

    func chopSuffix(count: Int = 1) -> String {
        return self.substringFromIndex(self.endIndex.advancedBy(count))
    }

Swift 3.0

    func chopPrefix(_ count: Int = 1) -> String {
        return self.substring(from: self.characters.index(self.startIndex, offsetBy: count))
    }

    func chopSuffix(_ count: Int = 1) -> String {
       return self.substring(to: self.characters.index(self.endIndex, offsetBy: -count))
    }

Swift 3.2

文字のコレクションとしての文字列の内容のビュー。

@available(swift, deprecated: 3.2, message: "Please use String or Substring directly")
public var characters: String.CharacterView
func chopPrefix(_ count: Int = 1) -> String {
    if count >= 0 && count <= self.count {
        return self.substring(from: String.Index(encodedOffset: count))
    }
    return ""
}

func chopSuffix(_ count: Int = 1) -> String {
    if count >= 0 && count <= self.count {
        return self.substring(to: String.Index(encodedOffset: self.count - count))
    }
    return ""
}

スウィフト4

extension String {

    func chopPrefix(_ count: Int = 1) -> String {
        if count >= 0 && count <= self.count {
            let indexStartOfText = self.index(self.startIndex, offsetBy: count)
            return String(self[indexStartOfText...])
        }
        return ""
    }

    func chopSuffix(_ count: Int = 1) -> String {
        if count >= 0 && count <= self.count {
            let indexEndOfText = self.index(self.endIndex, offsetBy: -count)
            return String(self[..<indexEndOfText])
        }
        return ""
    }
}

1
否定カウントをchopSuffix関数に追加するのを忘れたようです
Andy


10

最終結果をどのようにしたいかによって異なります(変異と非変異)。

Swift 4.1以降:

変異:

var str = "hello"
str.removeFirst() // changes str 

非変異:

let str = "hello"
let strSlice = str.dropFirst() // makes a slice without the first letter
let str2 = String(strSlice)

ノート:

  • nonmutatingわかりやすくするために、例に1つ追加のステップを入れています。主観的には、最後の2つのステップを組み合わせるとより簡潔になります。
  • 命名dropFirst、私は理解していた場合ので、私には少し奇妙に思えるスウィフトAPIの設計ガイドラインを正しくは、dropFirst本当にのようなものである必要がありdropingFirst、それはnonmutatingですので。ちょっとした考え :)。

1
確かに、それはそうあるべきですdroppingFirst-彼らはめちゃくちゃになりました!
Fattie

6

これはどうですか?

s.removeAtIndex(s.startIndex)

もちろん、これは文字列が変更可能であることを前提としています。削除された文字を返しますが、元の文字列を変更します。


6

以前の答えはかなり良いですが、今日のところ、これはSwift 4で文字列から最初の文字を削除する最も簡単な方法であると思います:

var line: String = "This is a string..."
var char: Character? = nil

char = line.removeFirst()

print("char = \(char)")  // char = T
print("line = \(line)")  // line = his is a string ...

1

私は箱から出して簡潔なことは何も知りませんが、簡単にprefixを実装することができます++、例えば、

public prefix func ++ <I: ForwardIndexType>(index: I) -> I {
    return advance(index, 1)
}

その後、あなたはそれをあなたの心の内容に非常に簡潔に使うことができます:

str.substringFromIndex(++str.startIndex)

1

Swift 2では、次の文字列拡張を使用します。

extension String
{
    func substringFromIndex(index: Int) -> String
    {
        if (index < 0 || index > self.characters.count)
        {
            print("index \(index) out of bounds")
            return ""
        }
        return self.substringFromIndex(self.startIndex.advancedBy(index))
    }
}

display.text = display.text!.substringFromIndex(1)

1

"en_US、fr_CA、es_US" .chopSuffix(5).chopPrefix(5)// "、fr_CA、"

extension String {
    func chopPrefix(count: Int = 1) -> String {
        return self.substringFromIndex(self.startIndex.advancedBy(count))
    }

    func chopSuffix(count: Int = 1) -> String {
        return self.substringToIndex(self.endIndex.advancedBy(-count))
    }
}

0

文字列から最初の文字を削除するには

let choppedString = String(txtField.text!.characters.dropFirst())

@JasonFoglia投票したかどうかはわかりません。反対票を投じた場合、詳しく説明していただけますか。
Hardik Thakkar 2017年

これを再確認したところ、正しいことがわかりました。これに適切に投票できるように、回答を編集しました。
Jason Foglia 2017

0

これは、拡張機能のSwift4クラッシュ保存バージョンであり、コミュニティchopPrefixに残りchopSuffixます...

extension String {
    func chopPrefix(_ count: Int = 1) -> String {
        return count>self.count ? self : String(self[index(self.startIndex, offsetBy: count)...])
    }
 }

0

Swift3

extension String {
    func chopPrefix(_ count: UInt = 1) -> String {
        return substring(from: characters.index(startIndex, offsetBy: Int(count)))
    }

    func chopSuffix(_ count: UInt = 1) -> String {
        return substring(to: characters.index(endIndex, offsetBy: -Int(count)))
    }
}

class StringChopTests: XCTestCase {
    func testPrefix() {
        XCTAssertEqual("original".chopPrefix(0), "original")
        XCTAssertEqual("Xfile".chopPrefix(), "file")
        XCTAssertEqual("filename.jpg".chopPrefix(4), "name.jpg")
    }

    func testSuffix() {
        XCTAssertEqual("original".chopSuffix(0), "original")
        XCTAssertEqual("fileX".chopSuffix(), "file")
        XCTAssertEqual("filename.jpg".chopSuffix(4), "filename")
    }
}

入力が負の値であるテストを追加する必要があると思います
Moustafa Baalbaki 2018年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.