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


122

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

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

我知道Int由于Unicode 的原因我们无法将字符串索引到字符串中,但是这种解决方案似乎非常冗长。我还有其他方法可以忽略吗?


3
实际上,可以advance通过强制转换display.text!为NSString 来避免整个事情。我并不是说这是一个好的解决方案-只是纠正可能的误解。使用NSString,您可以使用Int对其进行索引。-您无法使用Int进行索引的原因不是因为Unicode;这是因为一个角色可以包含多个复合代码点。
马特2015年

如果您这样做是为了大写,String则Swift 3将capitalized功能引入String
文斯·奥沙利文

Answers:


207

如果您使用的是Swift 3,则可以忽略此答案的第二部分。好消息是,这实际上现在又很简洁!仅使用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,但不能不从字符串characters属性中删除第一个字符,然后将结果转换回字符串。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]

2
它并不需要您进入Foundation世界。
马特2015年

2
它非常迅速/ fp。
David Berry 2015年

谢谢,这要优雅得多。我已经在Objective C中编程多年了,并且正在Swift中学习iTunes U Stanford iOS编程课程。我仍然有很多要学习的新范式。
SSteve

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构造函数以获取a 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:)创建有用的添加物以修剪a的开头和结尾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他们之前,这些功能会崩溃如果没有在字符串提供足够的字母。呼叫者有责任正确使用它们。这是一个有效的设计决策。可以编写它们以返回一个可选内容,然后调用者必须将其拆开。


斯威夫特2.x

在唉斯威夫特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))
    }
}

3
Swift的内置字符串操作多么复杂,仍然让我震惊。我的意思是这是基本的基本内容;它看起来不像我正在实现一个解析器。感谢您的扩展以简化此操作。苹果公司不只是将其添加到String类,这令人莫名其妙!也许它还在不断变化。
devios1 2016年

这就是他们所说的“进化”孩子。如果我们不必每天都处理它,那将很有趣。我知道String API保持原样是有原因的,但实际上,这确实必须推迟这么多潜在的转换为这种语言的可能。先前的评论者绝对正确-这应该是基本的基本内容。
昆丁·威利森

17

斯威夫特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))
    }

斯威夫特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))
    }

斯威夫特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
我想你忘了否定-count添加到chopSuffix功能
安迪·


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

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中使用以下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)

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

我重新检查了一下,发现它是正确的。我编辑了答案,以便可以对此进行正确的投票。
杰森·福里亚

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

迅捷3

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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.