如何将Swift中的字符转换为字符串?

22
我希望将一个 String 的首字母以字符串形式而不是字符形式返回:
func firstLetter() -> String {
    return self.title[0]
}

但是,我得到了Character is not convertible to String。如何正确地将Character转换为String?

这个答案建议创建一个下标扩展,但String的声明已经有了一个下标方法:

subscript (i: String.Index) -> Character { get }

这个答案是否过时,或者这两件事情是否不同?


1
你尝试过链接到的问题的答案了吗?例如,firstChar = string[string.startIndex] 应该可以工作。其他答案建议重载下标运算符,这也应该可以工作。- 对我来说,这看起来真的是同一个问题。 - Martin R
可能是在Swift编程语言中获取字符串的第n个字符的重复问题。 - Martin R
@mody 问题不在于标题,而在于:“我想将字符串的第一个字母作为字符串返回,而不是作为字符返回”。 - zaph
@mody 请查看Matt Gibson的答案。 - zaph
让我来说清楚一件事,三年过去了,没有人能明确回答这个问题:“如何将Swift字符转换为字符串”,即如何将String.Character转换为String,而不需要任何额外的“Optional(...)”填充?!荒谬。苹果用户不知道这种痛苦。Swift的辩护者想看着世界燃烧,因为苹果建议它应该燃烧。 - Saik Caskey
显示剩余3条评论
9个回答

26
为什么不使用字符串插值将字符转换为字符串?
return "\(firstChar)"

9
只需要第一个字符?那么如何这样做呢:
var str = "This is a test"
var result = str[str.startIndex..<str.startIndex.successor()] // "T": String

返回一个字符串(就像使用字符串的范围下标一样),只要至少有一个字符,它就能起作用。

这个版本稍微短些,可能会更快一点,但在我看来并不太易读:

var result = str[str.startIndex...str.startIndex]

6
从 Swift 2.3/3.0+ 开始,你可以像这样做:
func firstLetter() -> String {
    guard let firstChar = self.title.characters.first else {
        return ""  // If title is nil return empty string
    }
    return String(firstChar)
}

或者如果您可以接受可选字符串:

func firstLetter() -> String? {
    guard let firstChar = self.title.characters.first else {
       return nil
    }
    return String(firstChar)
}

更新至Swift 4,同时认为使用扩展更好

extension String{
func firstLetter() -> String {
    guard let firstChar = self.first else {
        return ""
    }
    return String(firstChar)
}

请解释一下,为什么这是错误的?正如我在这个方法的描述中所写的:“或者如果你愿意使用可选字符串”。它只是一个带有可选返回类型的版本。也许有人想要在方法外部进行可选链接,比如“if let”、“guard let”之类的操作。可选类型并没有错,它只是一种选择。 - nCod3d
是的,再读一遍我发现我的第一个评论并不是非常清晰,对此我感到抱歉。希望通过屏幕截图,您能够理解自己的错误并看到我的观点。 - Eric Aya
啊...你是对的 :) 我错了。[链接] (https://www.evernote.com/shard/s312/sh/c6f45143-7d00-44c9-844c-7580754f84cd/59385724bcfde1bb7a6b44196fc7f3c8) 很好,他们在Swift 3.0中为String init方法添加了一个参数名;) 我要更新我的代码.. - nCod3d
是的,我认为Swift团队中实现Optional符合StringLiteralConvertible协议这个决定是罕见的不好决策之一。这导致了许多问题,人们会认为自己有一个Optional,而实际上他们拥有的是字面意义上的字符串“Optional(something)”。你的例子很棘手,因为你将这个字面值包装在一个真正的Optional中。;) - Eric Aya
对于那些点踩的人:之前有个bug,现在已经修复好了,一切都按照预期运行。我稍微纠正了一下。如果你想知道的话,随便吧。 - nCod3d
显示剩余2条评论

3

我为类似问题进行了一些研究,发现可以通过以下方式从任何字符串中获取任何字符:

func charAsString(str:String, index:Int) -> String {
    return String(Array(str)[index])
}

对于第一个字符,您称之为
var firstCharAsString = firstLetter("yourString",0)

我对编程还不是很擅长,但我认为这可以满足你的需求。

编辑:

根据你的需求简化:

func firstChar(str:String) -> String {
    return String(Array(str)[0])
}

I hope that it's what you need


主要问题是如何将一个字符转换为字符串。 - Snowman
是的,String("c") 的作用就是将字符"c"转换为字符串。或者我可能没有理解问题的意思... - P1kachu
4
效率不高,因为它会创建一个包含字符串中所有字符的新数组。 - Martin R
有趣的是,Array(str) 创建的是 Characters 数组,而不是 utf8 unichars。我猜这是 Beta 4 中新增的功能。它必须使用 successor() 扫描整个字符串以确定 Characters,因此速度相对较慢。 - zaph
@Zaph 是的。Array(str) 调用 "init<S : Sequence where T == T>(_ s: S)" - 没有特定于 String 的数组初始化程序。它只需要任何序列并通过迭代添加元素。在这种情况下,String 只是一个特殊的 Sequence<Character>。 - hnh

0
我试图从解析的字符串中获取单个字符到一个字符串中。 所以我想要将helpAnswer中的B以字符串格式而不是字符格式输出,这样我就可以在文本框中打印出单个字符。 这很好用。我不知道它的效率如何。 但它能用。SWIFT 3.0
感谢大家的帮助.....
var helpAnswer = "ABC"
var String1 = ""
var String2 = ""
var String3 = ""


 String1 = (String(helpAnswer[helpAnswer.index(helpAnswer.startIndex, offsetBy: 0)]))
 String2 = (String(helpAnswer[helpAnswer.index(helpAnswer.startIndex, offsetBy: 1)]))
 String3 = (String(helpAnswer[helpAnswer.index(helpAnswer.startIndex, offsetBy: 1)])

0
let str = "My String"
let firstChar = String(str.characters.first!)

-1

这是我会做的:

func firstLetter() -> String {
var x:String = self.title[0]
    return x
}

1
无法运行:字符无法转换为字符串 - Snowman

-1
首先:您所提到的答案仍然相关。它为字符串添加了基于整数的索引(例如使用advance())。内置字符串下标仅支持双向索引(将它们视为游标而不是数组索引更合适)。这很可能是因为字符通常不是以此类形式存储在字符串结构中,而是作为UTF-8或UTF-16存储的。然后对字符进行定位访问需要解码(这也是为什么除了额外复制外,Array(string) [idx]真的很昂贵的原因)。

如果您真的只想要第一个字符,可以这样做:

extension String {
  var firstCharacterAsString : String {
    return self.startIndex == self.endIndex
      ? ""
      : String(self[self.startIndex])
  }
}

为什么要使用扩展而不是方法? - zaph
我投了反对票,因为在我看来,在本地层面上做某些事情比转向全球层面更好。将方法添加到基类往往会令人困惑。总的来说,我们在使用Objective-C时遇到的一个问题是没有充分的理由使用分类。顺便说一下,Swift文档使用术语“method”,尽管语法是“fund”,有点不协调。 - zaph
1
@Zaph。这是不正确的。扩展不像类别那样产生模块边界-只有在您将它们标记为公共(并且另一侧实际导入您的模块)时才会产生。事实上,这就是我喜欢使用扩展的原因之一,它使(特定于字符串的)函数局限于结构体而不是污染全局命名空间。请重新考虑;-> - hnh
当我看到 str.firstCharacterAsString 这个东西时,我就会想这是一个 String 内置的还是第三方方法。调用方法更清晰地说明了它是在哪里和由谁实现的。如果我从另一个项目中摘取包含此内容的代码,那么我需要获取扩展并不明显。正如我所说:在我看来。 - zaph
让我们在聊天中继续这个讨论:http://chat.stackoverflow.com/rooms/58443/discussion-between-hnh-and-zaph。 - hnh
《Swift编程语言》文档中有507个对method的引用,似乎并不清楚是使用“方法”还是“函数”作为首选术语。 - zaph

-2

最简单的方法是 return "\(self.title[0])"


1
这个不起作用:类型“String.Index”不符合协议“IntegerLiteralConvertible” - Snowman
对的,字符串没有随机访问索引。 '[0]' 中的 0 不能转换为字符串 '索引'。请使用 "(s[s.startIndex])" 或 "" + s[s.startIndex]。 - hnh

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接