From the department of “how did I not realise this sooner?!”:
1> "\r".count
$R0: Int = 1
2> "\n".count
$R1: Int = 1
3> "\r\n".count
$R2: Int = 1Yes, Swift treats the two bytes “\r\n” as a single character. This is actually super convenient a lot of the time, because it means algorithms that look for line breaks with isNewline just work, even on “Windows”-style text. Otherwise, you’d have to explicitly look for two isNewline characters in sequence and check if they are exactly “\r\n”.
But it does lead to some potentially surprising side-effects, like:
4> x.unicodeScalars.count
$R3: Int = 2
5> Array(x.unicodeScalars)
$R4: [String.UnicodeScalarView.Element] = 2 values {
[0] = U'\r'
[1] = U'\n'
}This isn’t surprising if you’re pretty familiar with how Unicode actually works – starting with the difference between graphemes (approximately what Swift calls a Character) and “scalars”, but I suspect it’ll catch some people out.


