web-dev-qa-db-de.com

Was ist der knappste Weg, um das erste Zeichen aus einer Zeichenfolge in Swift zu entfernen?

Ich möchte das erste Zeichen aus einer Zeichenfolge löschen. Das bisher Kleinste, was ich mir ausgedacht habe, ist:

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

Ich weiß, dass wir aufgrund von Unicode nicht in eine Zeichenfolge mit einer Int indizieren können, aber diese Lösung scheint furchtbar ausführlich zu sein. Gibt es einen anderen Weg, den ich übersehe?

88
SSteve

Wenn Sie Swift 3 verwenden, können Sie den zweiten Abschnitt dieser Antwort ignorieren. Eine gute Nachricht ist, das ist jetzt eigentlich wieder knapp! Verwenden Sie einfach die neue Methode remove (at :) von String.

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

myString // "Ello, World"

Ich mag die globale Funktion dropFirst() dafür.

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

Es ist kurz, klar und funktioniert für alles, was dem Sliceable-Protokoll entspricht.

Wenn Sie Swift 2 verwenden, hat sich diese Antwort geändert. Sie können dropFirst weiterhin verwenden, jedoch nicht, ohne das erste Zeichen aus der characters-Eigenschaft der Zeichenfolge zu löschen und das Ergebnis anschließend wieder in eine Zeichenfolge zu konvertieren. dropFirst ist auch eine Methode geworden, keine Funktion.

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

Eine andere Alternative besteht darin, die Suffixfunktion zu verwenden, um den UTF16View des Strings zu verbinden. Natürlich muss dieser auch nachträglich wieder in einen String umgewandelt werden.

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

All dies bedeutet, dass sich die ursprünglich von mir vorgeschlagene Lösung in neueren Versionen von Swift nicht als die prägnanteste Methode erwiesen hat. Ich empfehle, auf die Lösung von @chris mit removeAtIndex() zurückzugreifen, wenn Sie nach einer kurzen und intuitiven Lösung suchen.

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

original // Ello

Wie von @vacawama in den Kommentaren unten ausgeführt, besteht eine weitere Option, die den ursprünglichen String nicht ändert, in der Verwendung von substringFromIndex.

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

Wenn Sie ein Zeichen am Anfang und am Ende des Strings ablegen möchten, können Sie substringWithRange verwenden. Stellen Sie sicher, dass Sie sich vor dem Zustand schützen, wenn 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

Die letzte Zeile kann auch in Tiefschreibweise geschrieben werden.

let substring = original[newStartIndex..<newEndIndex]
174
Mick MacCallum

Update für Swift 4

In Swift 4 stimmt String wieder mit Collection überein, so dass es möglich ist, dropFirst und dropLast zu verwenden, um den Anfang und das Ende von Strings zu trimmen. Das Ergebnis ist vom Typ Substring. Sie müssen das also an den String-Konstruktor übergeben, um eine String-Anweisung zu erhalten:

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

dropFirst() und dropLast() benötigen auch eine Int, um die Anzahl der zu löschenden Zeichen anzugeben:

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

Wenn Sie mehr Zeichen zum Ablegen als in der Zeichenfolge angeben, wird das Ergebnis die leere Zeichenfolge ("") sein.

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

Update für Swift 3

Wenn Sie nur das erste Zeichen entfernen und die ursprüngliche Zeichenfolge ändern möchten, lesen Sie die Antwort von @ MickMacCallum. Wenn Sie im Prozess eine neue Zeichenfolge erstellen möchten, verwenden Sie substring(from:). Mit einer Erweiterung von String können Sie die Hässlichkeit von substring(from:) und substring(to:) ausblenden, um nützliche Ergänzungen zu erstellen, um den Anfang und das Ende einer String zu beschneiden:

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"

Wie vor dropFirst und dropLast stürzen diese Funktionen ab, wenn nicht genügend Buchstaben im String vorhanden sind. Der Anrufer hat die Pflicht, sie ordnungsgemäß zu verwenden. Dies ist eine gültige Designentscheidung. Man könnte sie schreiben, um eine Option zurückzugeben, die dann vom Anrufer ausgepackt werden müsste.


Swift 2.x

Leider sind in Swift 2 , dropFirst und dropLast (die bisher beste Lösung) nicht so bequem wie zuvor. Mit einer Erweiterung von String können Sie die Hässlichkeit von substringFromIndex und substringToIndex ausblenden:

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"

Wie vor dropFirst und dropLast stürzen diese Funktionen ab, wenn nicht genügend Buchstaben im String vorhanden sind. Der Anrufer hat die Pflicht, sie ordnungsgemäß zu verwenden. Dies ist eine gültige Designentscheidung. Man könnte sie schreiben, um eine Option zurückzugeben, die dann vom Anrufer ausgepackt werden müsste.


In Swift 1.2 müssen Sie chopPrefix wie folgt aufrufen:

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

oder Sie können den Funktionsdefinitionen einen Unterstrich _ hinzufügen, um den Parameternamen zu unterdrücken:

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))
    }
}
88
vacawama

Swift 2.2

'advance' ist nicht verfügbar: Rufen Sie die Methode 'advancedBy (n)' für den Index auf

    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

Eine Ansicht des Inhalts der Zeichenfolge als eine Sammlung von Zeichen.

@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 ""
}

Swift 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 ""
    }
}
15
Jaleel Nazir

In Swift 2 tun Sie dies:

let cleanedString = String(theString.characters.dropFirst())

Ich empfehle https://www.mikeash.com/pyblog/friday-qa-2015-11-06-why-is-swifts-string-api-so-hard.html , um Swift-Saiten zu verstehen .

12
jrc

Was ist damit?

s.removeAtIndex(s.startIndex)

Dies setzt natürlich voraus, dass Ihre Zeichenfolge veränderbar ist. Es gibt das Zeichen zurück, das entfernt wurde, ändert jedoch die ursprüngliche Zeichenfolge.

6
chris

Hängt davon ab, was das Endergebnis sein soll (mutieren vs. nicht mutieren).

Ab Swift 4.1:

Mutieren:

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

Nicht mutierend:

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

Anmerkungen:

  • Ich habe im nonmutating-Beispiel der Klarheit halber einen zusätzlichen Schritt hinzugefügt. Subjektiv wäre die Kombination der letzten beiden Schritte prägnanter. 
  • Die Benennung von dropFirst erscheint mir etwas seltsam, denn wenn ich die Swift API Design Guidelines richtig verstehe, sollte dropFirst wirklich etwas wie dropingFirst sein, da es nicht mutierend ist. Nur ein Gedanke :). 
5
jason z

Die vorherigen Antworten sind ziemlich gut, aber ich denke, dass dies der beste Weg ist, das erste Zeichen aus einer Zeichenfolge in Swift 4 zu entfernen:

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 ...
2
ByteSlinger

Ich kenne nichts prägnanteres aus der Box, aber Sie könnten leicht das Präfix ++ implementieren, z.

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

Danach können Sie es nach Herzenslust sehr knapp verwenden:

str.substringFromIndex(++str.startIndex)
1
Gregory Higley

"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))
    }
}
1
Andy

Verwenden Sie in Swift 2 diese String-Erweiterung:

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
ChikabuZ

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")
    }
}
0
neoneye

Hier ist eine Swift4 crash save Version der Erweiterung chopPrefix, die chopSuffix der Community überlässt.

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

So entfernen Sie das erste Zeichen aus der Zeichenfolge

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