22

I want to return the first letter of a String as a String instead of as a Character:

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

However, with the above I get Character is not convertible to String. What's the right way to convert a Character to a String?

This answer suggests creating a subscript extension, but the declaration for String already has a subscript method:

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

Is that answer outdated, or are these two different things?

Community
  • 1
  • 1
Snowman
  • 31,411
  • 46
  • 180
  • 303
  • 1
    Have you tried the answers to the question that you linked to? For example, `firstChar = string[string.startIndex]` should work. Other answers suggest to *overload* the subscript operator, which should also work. - This looks really like the same question to me. – Martin R Jul 31 '14 at 15:20
  • possible duplicate of [Get nth character of a string in Swift programming language](http://stackoverflow.com/questions/24092884/get-nth-character-of-a-string-in-swift-programming-language) – Martin R Jul 31 '14 at 15:22
  • @MartinR the question is not how to get the nth character but how to convert a Character to a String – Snowman Jul 31 '14 at 15:37
  • @mody The question, not the title is: "I want to return the first letter of a String as a String instead of as a Character". – zaph Jul 31 '14 at 16:15
  • @Zaph by using the built in subscript method which returns a Character and converting it to a String... – Snowman Jul 31 '14 at 16:37
  • @mody See the answer by Matt Gibson. – zaph Jul 31 '14 at 16:44
  • This answer http://stackoverflow.com/a/24178591/1187415 to the other question has methods to get a substring (very similar to Matt's answer below). – Martin R Jul 31 '14 at 16:47
  • So let me get this straight, 3 years later and no one can definitively answer the question "How to convert Swift Character to String" i.e., how to convert String.Character to String, without any extra "Optional(...)" padding?!. Ridiculous. Apple users have no idea of the struggle. Swift apologists want to watch the world burn because Apple recommended it should burn. – Saik Caskey Oct 02 '17 at 10:52

9 Answers9

26

Why don't you use String interpolation to convert the Character to a String?

return "\(firstChar)"
Sascha L.
  • 347
  • 2
  • 6
9

Just the first character? How about:

var str = "This is a test"
var result = str[str.startIndex..<str.startIndex.successor()] // "T": String

Returns a String (as you'd expect with a range subscript of a String) and works as long as there's at least one character.

This is a little shorter, and presumably might be a fraction faster, but to my mind doesn't read quite so clearly:

var result = str[str.startIndex...str.startIndex]
Matt Gibson
  • 37,886
  • 9
  • 99
  • 128
6

As of Swift 2.3/3.0+ you can do something like this:

func firstLetter() -> String {
    guard let firstChar = self.title.characters.first else {
        return ""  // If title is nil return empty string
    }
    return String(firstChar)
}

Or if you're OK with optional String:

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

Update for Swift 4, also think an extension is better

extension String{
func firstLetter() -> String {
    guard let firstChar = self.first else {
        return ""
    }
    return String(firstChar)
}
Sergio Trejo
  • 632
  • 8
  • 23
nCod3d
  • 667
  • 1
  • 10
  • 12
  • Please explain, why is this wrong? As I wrote in description to this method : "Or if you're OK with optional String". Its just a version with Optional return type. Maybe someone would want to do optional chaining like 'if let', 'guard let' outside the method or something. There is nothing wrong about Optional type, its just an option. – nCod3d Aug 24 '16 at 12:07
  • I have explained in my comment. But maybe I wasn't clear. :) Look at this screenshot: https://www.evernote.com/l/AOzlMTJ9ky9CY65GgrWrGAc2z_UPA9eS5_o What you return is the *literal* String "Optional("y")" *inside* an Optional. – Eric Aya Aug 24 '16 at 12:09
  • And yeah, reading it again I see that my first comment wasn't super clear, sorry for that. Hopefully with the screenshot you will understand your mistake and see my point. – Eric Aya Aug 24 '16 at 12:13
  • Ahhhh... You were right :) My bad. [link] (https://www.evernote.com/shard/s312/sh/c6f45143-7d00-44c9-844c-7580754f84cd/59385724bcfde1bb7a6b44196fc7f3c8) good thing that they've added an argument name for String init method in Swift 3.0 ;) Gonna update my code.. – nCod3d Aug 24 '16 at 12:42
  • Yeah, having Optional conforming to StringLiteralConvertible is one of the rare bad decisions the Swift team has made IMO. This causes many issues where people think they have an Optional where they actually have the literal *string* "Optional(something)" instead. Your example was tricky because you then wrapped this literal inside a real Optional. ;) – Eric Aya Aug 24 '16 at 12:46
  • I've created a spy/bug :)) – nCod3d Aug 24 '16 at 12:57
  • For people who down-votes: there was a bug, now its all good and working as intended...I sorta corrected it...In case you'll wonder..whatever... – nCod3d Oct 19 '16 at 18:57
3

I did some researches for the same type of question, and I found this way to get any character from any string:

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

and for the first character you call

var firstCharAsString = firstLetter("yourString",0)

I am a not very good at programming yet but I think that this will do what you want

EDIT:

Simplified for your need:

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

I hope that it's what you need

P1kachu
  • 1,077
  • 3
  • 11
  • 33
  • The main question is how to convert a Character to a String though. – Snowman Jul 31 '14 at 15:13
  • Yes, that is what `String("c")` does, doesn't it ? It converts "c" from a Character to a string. Or maybe I don't understand the question... – P1kachu Jul 31 '14 at 15:20
  • 4
    Not very efficient, because it creates a new array containing all characters from the string. – Martin R Jul 31 '14 at 15:23
  • Interesting that `Array(str)` creates an array of `Characters`, not utf8 unichars. I suspect new to Beta 4. It must scan the entire String with `successor()` to determine the `Characters` and thus reasonably slow. – zaph Jul 31 '14 at 16:40
  • @Zaph Yes. Array(str) invokes "init(_ s: S)" - there is no String specific array initializer. It just takes any Sequence and adds the elements by iterating over it. String is just a special Sequence in this context. – hnh Jul 31 '14 at 17:10
0
let str = "My String"
let firstChar = String(str.characters.first!)
Warif Akhand Rishi
  • 23,920
  • 8
  • 80
  • 107
0

I was trying to get single characters from a parsed String into a String. So I wanted B from helpAnswer in String format not CHARACTER format, so I could print out the individual characters in a text box. This works great. I don't know about the efficiency of it. But it works. SWIFT 3.0
Thanks for everyones help.....

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)])
ChopinBrain
  • 121
  • 2
  • 14
-1

This is what I would do:

func firstLetter() -> String {
var x:String = self.title[0]
    return x
}
Coder404
  • 742
  • 2
  • 7
  • 21
-1

First: The answer you refer to is still relevant. It adds Integer based indices to String (e.g. using advance()). The builtin String subscript only supports BidirectionalIndices (think of them more like cursors, not as array-indices). This is likely because the Characters are not usually stored as such in the String structure, but as UTF-8 or UTF-16. Positional access to the characters then requires decoding (which is why - in addition to the extra copying - Array(string)[idx] is really expensive).

If you really just want the first char, you could do this:

extension String {
  var firstCharacterAsString : String {
    return self.startIndex == self.endIndex
      ? ""
      : String(self[self.startIndex])
  }
}
hnh
  • 13,957
  • 6
  • 30
  • 40
  • Why an extension and not just a method? – zaph Jul 31 '14 at 16:12
  • I down voted because IMO doing something on a local level is better than moving to a global level. Adding a method to a base class tends to be confusing. In general one issue we have had with Objective-C was the use of Categories for no good reason. BTW, the Swift documents use the term `method` even though the syntax is `fund`, somewhat of a disconnect. – zaph Jul 31 '14 at 17:20
  • 1
    @Zaph. This is incorrect. Extensions don't spawn module boundaries like categories do - only if you mark them public (and the other side actually imports your module). As a matter of fact that is one reason why I prefer an extension, it keeps the (String specific) function local to the structure instead of polluting the global namespace. Please reconsider ;-> – hnh Jul 31 '14 at 17:26
  • When I see `str.firstCharacterAsString` I have to wonder is that a `String` builtin for a 3rd party method. A method invocation is more clear where and by whom it is implemented. If I pick up a bit of code from another project that contains this it is nit clear I need to also get the `Extension`. As I stated: IMO. – zaph Jul 31 '14 at 17:35
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/58443/discussion-between-hnh-and-zaph). – hnh Jul 31 '14 at 17:36
  • *The Swift Programming Language* documents has 507 references to `method`, it seems clear that it is **not clear** if 'method' or 'function' is the preferred nomenclature. – zaph Jul 31 '14 at 17:40
-2

The simplest way is return "\(self.title[0])".

NRitH
  • 13,441
  • 4
  • 41
  • 44
  • 1
    This doesn't work: `Type 'String.Index' does not conform to protocol 'IntegerLiteralConvertible'` – Snowman Jul 31 '14 at 15:12
  • Right, a string doesn't have a random access index. The 0 in '[0]' cannot be converted to a String 'Index'. Do this "\(s[s.startIndex])" or "" + s[s.startIndex] – hnh Jul 31 '14 at 15:38