在 Swift 中,从字符串中删除第一个字符的最简洁的方法是什么?

我想从字符串中删除第一个字符。到目前为止,我想到的最简洁的说法是:

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

我知道由于 Unicode 的原因,我们不能使用 Int对字符串进行索引,但是这个解决方案似乎非常冗长。还有其他我没注意到的地方吗?

118672 次浏览

我知道没有比这更简洁的了,但是你可以很容易地实现前缀 ++,例如,

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

然后你就可以尽情地简洁地使用它了:

str.substringFromIndex(++str.startIndex)

这个怎么样?

s.removeAtIndex(s.startIndex)

当然,这里假设您的字符串是可变的。它返回已删除的字符,但是更改了原始字符串。

如果您使用的是 Swift 3,那么可以忽略这个答案的第二部分。好消息是,现在又变得简洁了!只需使用 String 的新 move (at:)方法。

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


myString // "ello, World"

我喜欢这个全局 dropFirst()函数。

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

它简短,清晰,适用于任何符合切片协议的东西。

如果您使用的是 Swift 2 ,那么这个答案已经更改。您仍然可以使用 dropFirst,但是必须删除字符串 characters属性中的第一个字符,然后将结果转换回 String。DropFirst 也变成了一个方法,而不是一个函数。

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

另一种方法是使用后缀函数拼接字符串的 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 在下面的注释中指出的,另一个不修改原始 String 的选项是使用 substringFromIndex。

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

或者,如果您正好要从 String 的开头和结尾删除一个字符,则可以使用 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]

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"

与之前的 dropFirstdropLast一样,如果字符串中没有足够的字母,这些函数也会崩溃。调用者有责任正确使用它们。这是一个有效的设计决策。人们可以写它们来返回一个可选的,然后必须由调用者取消包装。


Swift 2. x

遗憾的是,Swift 2dropFirstdropLast(以前的最佳解决方案)不再像以前那样方便。通过 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"

与之前的 dropFirstdropLast一样,如果字符串中没有足够的字母,这些函数也会崩溃。调用者有责任正确使用它们。这是一个有效的设计决策。人们可以写它们来返回一个可选的,然后必须由调用者取消包装。


Swift 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))
}
}

在 Swift 2中,这样做:

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

我推荐使用 https://www.mikeash.com/pyblog/friday-qa-2015-11-06-why-is-swifts-string-api-so-hard.html来理解 Swift 字符串。

在 Swift 2中使用这个 String 扩展:

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)

Swift 2.2

“ forward”不可用: 调用索引上的“ Advanced By (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 ""
}

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

“ en _ US,fr _ CA,es _ US”

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

从字符串中删除第一个字符

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

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

这里是一个 Swift4崩溃保存版本的 chopPrefix扩展,留给社区的 chopSuffix..。

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

以前的答案都很不错,但是到今天为止,我认为这可能是从 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 ...

这取决于您希望最终结果是什么(变异还是非变异)。

截至 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示例中添加了一个额外的步骤。从主观上讲,将最后两个步骤结合起来会更简洁。
  • dropFirst的命名对我来说似乎有点奇怪,因为如果我正确理解了 快速 API 设计指南,那么 dropFirst应该是类似于 droppingFirst的东西,因为它是非变异的。只是一个想法:)。