Skip to content

Comment on Swift Blogparent

Comments

I've been using it for my latest project. Haven't done anything too fancy with it yet. Lack of automatic type conversion between ints and floats is driving me up the wall a little bit, but maybe that's a personal flaw rather than a flaw with the language. String manipulation is also incredibly confusing to me: I have yet to figure out how to get the number of characters in a string, or how to generate a random character. Other than that, it feels pretty nice to use.

EDIT: also how to get character n in a string.

You can add your own operator overloading of different number types to mitigate the casting required see: https://github.com/jquave/EasyCast

You can also add your own String extension for length and index character at in a String with:

    extension String {
        var length: Int { return countElements(self) }

        subscript (i: Int) -> String {
            return String(Array(self)[i])
        }
    }
Which will now let you use `.length` on strings, e.g:
    "Cat".length; //3
And get the character at index with:
    "Cat"[1]; //a
I've more useful extensions at: https://github.com/mythz/swift-linq-examples/blob/master/src...

Which enables LINQ-like querying in Swift: https://github.com/mythz/swift-linq-examples

In general, there are good reasons to not do implicit casts, especially between ints and floats. For one, it's actually a fairly expensive operation.

Eh, not really. Certainly conversions from int->long should be implicit (I don't know if they are in Swift, though).

Presumably you mean there are good reasons not to do implicit casts.

.utf16count will get you the number of characters in a simple string[0].

[0] What is a character especially in various non-latin scripts? I think it is well handled in Swift, from what I can see it has been considered carefully but I haven't yet needed to get my head round it.

Edit: Corrected - too fast in the playground and actually checked an array. .utf16count not .count

I believe Apple says to use countElements(string) instead of string.count

Yeah, I understand why they did it, but the fact of the matter is that I'm using ASCII 99% of the time.

But not the rest of the world.

    countElements(string)
returns the number of Unicode code points in a string. I'm not sure about the random character, though. Swift is very much oriented towards Unicode rather than bytes when it comes to strings.

Here is a great article about strings in Swift: http://oleb.net/blog/2014/07/swift-strings/

Short story: “number of characters” and “nth character” are more complicated questions than you might think when you deal with full Unicode text.

Right, but it's a problem when you're mostly dealing with ASCII identifiers and so forth.

Looks like a great article, thanks!

To get the number of characters in a string, call countElements(string). To generate a random character, your best bet (IMO, someone else may have a more elegant solution) is to have an array (or dictionary) or characters and use a random number generator to select a character from the structure.

It would be easier to do this from an array of strings but I found an ugly inefficient way to do it from the characters in an arbitrary string:

  func randChar(alphabet:String?)->String {
    let alpha = alphabet ? alphabet! : "abcdefghijklmnopqrstuvwxyz"
    let rand:Int = Int(arc4random_uniform(UInt32(countElements(alpha))))
    var gen = alpha.generate()
    for i in 0..<rand {
        gen.next()
    }
    return String(gen.next()!)
  }
mikeash obviously has the answer if the codepoints are consecutive.

This was quite annoying to do, more so than I expected. If you convert to UTF16 view you can alter the index by advanceBy but then I couldn't find an easy way to convert back from the UInt16 to a Character/String but mikeash also covers that. However I'm not sure that conversion to UTF16 is any less work internally than iterating through the index.

If you have a range of unicode code points that you want to select from, you can generate a random number in that range and then turn it into a one-character string like so:

    let codepoint: UInt32 = ...random choice code here...
    let scalar = UnicodeScalar(codepoint)
    let string = String(scalar)
AboutSource Built by g1lg1l

Hackerly is an independent reader for Hacker News, built on the public HN API. Not affiliated with Y Combinator.