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

What is the most succinct way to remove the first character from a string in Swift?

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

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

我知道由于Unicode我们无法使用Int索引到字符串,但是这种解决方案似乎太冗长了。 我还有其他方法可以忽略吗?


如果您使用的是Swift 3,则可以忽略此答案的第二部分。好消息是,这实际上现在又很简洁!仅使用String的新remove(at :)方法。

1
2
3
4
var myString ="Hello, World"
myString.remove(at: myString.startIndex)

myString //"ello, World"

我喜欢全局dropFirst()函数。

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

它简短,清晰,适用于符合Sliceable协议的任何内容。

如果您使用的是Swift 2,则此答案已更改。您仍然可以使用dropFirst,但不能不从字符串characters属性中删除第一个字符,然后将结果转换回字符串。 dropFirst也已成为方法,而不是函数。

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

另一种选择是使用后缀函数来拼接字符串的UTF16View。当然,此后也必须将其转换回字符串。

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

这就是说,我最初提供的解决方案并不是在较新版本的Swift中做到这一点的最简洁的方法。如果您正在寻找一个简短而直观的解决方案,我建议您使用removeAtIndex()放弃@chris'解决方案。

1
2
3
4
var original ="Hello" // Hello
let removedChar = original.removeAtIndex(original.startIndex)

original // ello

正如@vacawama在下面的注释中所指出的,不修改原始String的另一个选项是使用substringFromIndex。

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

或者,如果您恰巧希望将某个字符从String的开头和结尾删除,则可以使用substringWithRange。只要确保startIndex + n > endIndex - m时不要出现这种情况。

1
2
3
4
5
6
let original ="Hello" // Hello

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

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

最后一行也可以使用下标符号书写。

1
let substring = original[newStartIndex..<newEndIndex]


Swift 4更新

在Swift 4中,String再次符合Collection,因此可以使用dropFirstdropLast修剪字符串的开头和结尾。结果的类型为Substring,因此您需要将其传递给String构造函数以获取String

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

dropFirst()dropLast()也采用Int来指定要删除的字符数:

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

如果指定要删除的字符多于字符串中的字符,则结果将是空字符串("")。

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

Swift 3更新

如果您只想删除第一个字符并想要更改原始字符串,请参阅@ MickMacCallum的答案。如果要在此过程中创建新字符串,请使用substring(from:)。通过扩展String,您可以隐藏substring(from:)substring(to:)的丑陋之处,以创建有用的附加内容以修剪String的开头和结尾:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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一样,如果字符串中没有足够的字母,这些函数将崩溃。呼叫者有责任正确使用它们。这是一个有效的设计决策。可以编写它们以返回一个可选内容,然后调用者必须将其解包。

斯威夫特2.x

不幸的是,在Swift 2中,dropFirstdropLast(以前的最佳解决方案)并不像以前那样方便。通过扩展String,您可以隐藏substringFromIndexsubstringToIndex的丑陋之处:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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

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

或者您可以在函数定义中添加下划线_以取消参数名称:

1
2
3
4
5
6
7
8
9
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))
    }
}


斯威夫特2.2

'advance' is unavailable: call the 'advancedBy(n)' method on the index

1
2
3
4
5
6
7
    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))
    }

斯威夫特3.0

1
2
3
4
5
6
7
    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))
    }

斯威夫特3.2

A view of the string's contents as a collection of characters.

1
2
@available(swift, deprecated: 3.2, message:"Please use String or Substring directly")
public var characters: String.CharacterView
1
2
3
4
5
6
7
8
9
10
11
12
13
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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""
    }
}


在Swift 2中,执行以下操作:

1
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 4.1开始:

变异:

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

非变异:

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

笔记:

  • 为了清楚起见,我在nonmutating示例中增加了一个步骤。从主观上讲,将最后两个步骤结合起来会更简洁。
  • dropFirst的命名对我来说有点奇怪,因为如果我正确地理解了《 Swift API设计指南》,dropFirst应该确实像dropingFirst一样,因为它是不变的。只是一个想法 :)。


前面的答案非常好,但是到目前为止,我认为这可能是在Swift 4中从字符串中删除第一个字符的最简洁的方法:

1
2
3
4
5
6
7
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
s.removeAtIndex(s.startIndex)

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


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

1
2
3
4
5
6
7
8
9
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))
    }
}

在Swift 2中使用以下String扩展名:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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
2
3
public prefix func ++ <I: ForwardIndexType>(index: I) -> I {
    return advance(index, 1)
}

之后,您可以非常简洁地使用它:

1
str.substringFromIndex(++str.startIndex)

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

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

迅捷3

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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")
    }
}


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

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