Iterate through alphabet in Swift - ios

in Obj-C it was possible to iterate through alphabet with:
for (char x='A'; x<='Z'; x++) {
In Swift this isn't possible. Any idea how I could do this?

In Swift, you can iterate chars on a string like this:
Swift 2
for char in "abcdefghijklmnopqrstuvwxyz".characters {
println(char)
}
Swift 1.2
for char in "abcdefghijklmnopqrstuvwxyz" {
println(char)
}
There might be a better way though.

It's slightly cumbersome, but the following works (Swift 3/4):
for value in UnicodeScalar("a").value...UnicodeScalar("z").value { print(UnicodeScalar(value)!) }
I suspect that the problem here is that the meaning of "a"..."z" could potentially be different for different string encodings.
(Older stuff)
Also cumbersome, but without the extra intermediate variable:
for letter in map(UnicodeScalar("a").value...UnicodeScalar("z").value, {(val: UInt32) -> UnicodeScalar in return UnicodeScalar(val); })
{
println(letter)
}

for i in 97...122{println(UnicodeScalar(i))}

Swift 4.2 version is much easier
for char in "abcdefghijklmnopqrstuvwxyz" {
print(char)
}

Updated for Swift 3.0 and higher
let startChar = Unicode.Scalar("A").value
let endChar = Unicode.Scalar("Z").value
for alphabet in startChar...endChar {
if let char = Unicode.Scalar(alphabet) {
print(char)
}
}

Details
Swift 5.3
Version 12.4 (12D4e)
Solution
extension ClosedRange where Bound == UnicodeScalar {
func toArray() -> [UnicodeScalar] {
(lowerBound.value...upperBound.value).compactMap { UnicodeScalar($0) }
}
}
extension ClosedRange where Bound == String {
func toArray() -> [UnicodeScalar]? {
guard let lower = lowerBound.first?.unicodeScalars.first,
let upper = upperBound.first?.unicodeScalars.first else { return nil }
return (lower...upper).toArray()
}
}
Usage
("a"..."z").toArray() // option 1
(UnicodeScalar("a")...UnicodeScalar("z")).toArray() // option 2

This solution works with Swift 3.0, and will either print out the values per OP request:
"ABCDEFGHIJKLMNOPQRSTUVWXYZ".characters.flatMap { print($0) }
Or provide you with an array of letters:
let alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".characters.flatMap { $0.description }

"Pure functional" Swift 5 way:
(Unicode.Scalar("A").value...Unicode.Scalar("Z").value).forEach({
let letter = Unicode.Scalar($0)!
print(letter)
/* do other stuff with letter here */
})

Did you try this one ?
for var myChar:CChar = 65 ; myChar <= 90 ; ++myChar {
let x:String = String(format: "%c", myChar)
println(x)
}
If you already know the character code

Related

Swift: Remove specific characters of a string only at the beginning

i was looking for an answer but haven't found one yet, so:
For example: i have a string like "#blablub" and i want to remove the # at the beginning, i can just simply remove the first char. But, if i have a string with "#####bla#blub" and i only want to remove all # only at the beginning of the first string, i have no idea how to solve that.
My goal is to get a string like this "bla#blub", otherwise it would be to easy with replaceOccourencies...
I hope you can help.
Swift2
func ltrim(str: String, _ chars: Set<Character>) -> String {
if let index = str.characters.indexOf({!chars.contains($0)}) {
return str[index..<str.endIndex]
} else {
return ""
}
}
Swift3
func ltrim(_ str: String, _ chars: Set<Character>) -> String {
if let index = str.characters.index(where: {!chars.contains($0)}) {
return str[index..<str.endIndex]
} else {
return ""
}
}
Usage:
ltrim("#####bla#blub", ["#"]) //->"bla#blub"
var str = "###abc"
while str.hasPrefix("#") {
str.remove(at: str.startIndex)
}
print(str)
I recently built an extension to String that will "clean" a string from the start, end, or both, and allow you to specify a set of characters which you'd like to get rid of. Note that this will not remove characters from the interior of the String, but it would be relatively straightforward to extend it to do that. (NB built using Swift 2)
enum stringPosition {
case start
case end
case all
}
func trimCharacters(charactersToTrim: Set<Character>, usingStringPosition: stringPosition) -> String {
// Trims any characters in the specified set from the start, end or both ends of the string
guard self != "" else { return self } // Nothing to do
var outputString : String = self
if usingStringPosition == .end || usingStringPosition == .all {
// Remove the characters from the end of the string
while outputString.characters.last != nil && charactersToTrim.contains(outputString.characters.last!) {
outputString.removeAtIndex(outputString.endIndex.advancedBy(-1))
}
}
if usingStringPosition == .start || usingStringPosition == .all {
// Remove the characters from the start of the string
while outputString.characters.first != nil && charactersToTrim.contains(outputString.characters.first!) {
outputString.removeAtIndex(outputString.startIndex)
}
}
return outputString
}
A regex-less solution would be:
func removePrecedingPoundSigns(s: String) -> String {
for (index, char) in s.characters.enumerate() {
if char != "#" {
return s.substringFromIndex(s.startIndex.advancedBy(index))
}
}
return ""
}
A swift 3 extension starting from OOPer's response:
extension String {
func leftTrim(_ chars: Set<Character>) -> String {
if let index = self.characters.index(where: {!chars.contains($0)}) {
return self[index..<self.endIndex]
} else {
return ""
}
}
}
As Martin R already pointed out in a comment above, a regular expression is appropriate here:
myString.replacingOccurrences(of: #"^#+"#, with: "", options: .regularExpression)
You can replace the inner # with any symbol you're looking for, or you can get more complicated if you're looking for one of several characters or a group etc. The ^ indicates it's the start of the string (so you don't get matches for # symbols in the middle of the string) and the + represents "1 or more of the preceding character". (* is 0 or more but there's not much point in using that here.)
Note the outer hash symbols are to turn the string into a raw String so escaping is not needed (though I suppose there's nothing that actually needs to be escaped in this particular example).
To play around with regex I recommend: https://regexr.com/

Splitting a Swift String using a multi-Character String in Swift 2

I understand that I can fallback to the NSString function componentsSeparatedByString, and so perhaps this is a nitpick, but one of the things I like about Swift is that it is designed around brevity and short syntax.
I was really hoping I could just: var parts = myString.characters.split("${") but that function only works for a single Character, not a two Character string. I even tried var parts = myString.characters.split { $0 == "${" } but that is expecting a single Character as the delimiter and not a full String. :(
Is there an api function that I'm missing or do I need to stick with the the old NSString bridged functions?
Here's a rather simple-minded approach that makes it possible to use Swift split on a single character:
extension String {
mutating func replace(target:String, with:String) {
while let r = self.rangeOfString(target) {
self.replaceRange(r, with: with)
}
}
func split(separator:String) -> Array<String> {
var s = self
s.replace(separator, with:"☞") // arbitrary improbable character :)
return s.characters.split("☞").map{String($0)}
}
}
var s = "the${cat${sat${on${the${mat"
let arr = s.split("${")
However, rangeOfString is actually a Foundation method on NSString; if you don't import Foundation (or UIKit), that code won't compile. So in reality it's no improvement over just calling componentsSeparatedByString. I don't actually understand your objection to it in the first place; Swift has holes exactly because it expects Foundation to be backing it up and filling those holes.
'pure' Swift's solution where import Foundation is NOT required and arbitrary improbable character doesn't exists
let str = "t{he${cat${sat${on${the${mat"
let splitBy = "${"
extension String {
func split(splitBy: String)->[String] {
if self.isEmpty { return [] }
var arr:[String] = []
var tmp = self
var tmp1 = ""
var i = self.startIndex
let e = self.endIndex
let c = splitBy.characters.count
while i < e {
let tag = tmp.hasPrefix(splitBy)
if !tag {
tmp1.append(tmp.removeAtIndex(tmp.startIndex))
i = i.successor()
} else {
tmp.removeRange(Range(start: tmp.startIndex, end: tmp.startIndex.advancedBy(c)))
i = i.advancedBy(c)
arr.append(tmp1)
tmp1 = ""
}
}
arr.append(tmp1)
return arr.filter{ !$0.isEmpty }
}
}
let arr = str.split(splitBy) // ["t{he", "cat", "sat", "on", "the", "mat"]
If you have Foundation imported, you can use the components(separatedBy:) method to accomplish that.
let str = "Foo, Bar, Baz"
str.components(separatedBy: ", ")
Here are the docs.
(Tested on Ubuntu Linux)

Cannot invoke substringToIndex with an arguement list type int

I'm trying to get this line to work:
textView.text = textView.text.substringToIndex(count(textView.text.utf16) - 1)
error: Cannot invoke substringToIndex with an arguement list type int
substringToIndex takes a String.Index which is different from an Int. If you want to take the whole string minus the last character, you could do
textView.text = textView.text.substringToIndex(advance(textView.text.endIndex, -1))
To advance David's answer, the issue basically arose due to difference between Foundation's NSString class and Swift's String type.
The method belongs to type String needs <String.Index>, because string handling in Swift is different from NSString's implementation.
To clarify, NSString instances do not use Unicode characters, whereas Swift needs comprehensive approach to Strings regarding usage of Unicode characters. Hence, you should be careful when casting Strings to NSStrings, or vice versa.
You can use this extension:
Swift 2.3
extension String
{
func substringToIndex(index: Int) -> String
{
if (index < 0 || index > self.characters.count)
{
print("index \(index) out of bounds")
return ""
}
return self.substringToIndex(self.startIndex.advancedBy(index))
}
}
Swift 3
extension String
{
func substring(to index: Int) -> String
{
if (index < 0 || index > self.characters.count)
{
print("index \(index) out of bounds")
return ""
}
return self.substring(to: self.characters.index(self.startIndex, offsetBy: index))
}
}
And use:
textView.text = textView.text.substringToIndex(textView.text.characters.count - 1)
Use below code for SWIFT 3:-
if textView.text.characters.count > 100 {
let tempStr = textView.text
let index = tempStr?.index((tempStr?.endIndex)!, offsetBy: 100 - (tempStr?.characters.count)!)
textView.text = tempStr?.substring(to: index!)
}
}

Swift switch statement for matching substrings of a String

Im trying to ask for some values from a variable.
The variable is going to have the description of the weather and i want to ask for specific words in order to show different images (like a sun, rain or so)
The thing is i have code like this:
if self.descriptionWeather.description.rangeOfString("Clear") != nil
{
self.imageWeather.image = self.soleadoImage
}
if self.descriptionWeather.description.rangeOfString("rain") != nil
{
self.imageWeather.image = self.soleadoImage
}
if self.descriptionWeather.description.rangeOfString("broken clouds") != nil
{
self.imageWeather.image = self.nubladoImage
}
Because when i tried to add an "OR" condition xcode gives me some weird errors.
Is it possible to do a swich sentence with that? Or anyone knows how to do add an OR condition to the if clause?
I had a similar problem today and realized this question hasn't been updated since Swift 1! Here's how I solved it in Swift 4:
switch self.descriptionWeather.description {
case let str where str.contains("Clear"):
print("clear")
case let str where str.contains("rain"):
print("rain")
case let str where str.contains("broken clouds"):
print("broken clouds")
default:
break
}
Swift 5 Solution
func weatherImage(for identifier: String) -> UIImage? {
switch identifier {
case _ where identifier.contains("Clear"),
_ where identifier.contains("rain"):
return self.soleadoImage
case _ where identifier.contains("broken clouds"):
return self.nubladoImage
default: return nil
}
}
You can do this with a switch statement using value binding and a where clause. But convert the string to lowercase first!
var desc = "Going to be clear and bright tomorrow"
switch desc.lowercaseString as NSString {
case let x where x.rangeOfString("clear").length != 0:
println("clear")
case let x where x.rangeOfString("cloudy").length != 0:
println("cloudy")
default:
println("no match")
}
// prints "clear"
Swift language has two kinds of OR operators - the bitwise ones | (single vertical line), and the logical ones || (double vertical line). In this situation you need a logical OR:
if self.descriptionWeather.description.rangeOfString("Clear") != nil || self.descriptionWeather.description.rangeOfString("clear") != nil {
self.imageWeather.image = self.soleadoImage
}
Unlike Objective-C where you could get away with a bitwise OR in exchange for getting a slightly different run-time semantic, Swift requires a logical OR in the expression above.
If you do this a lot, you can implement a custom ~= operator that defines sub-string matching. It lends itself to this nice syntax:
switch "abcdefghi".substrings {
case "def": // calls `"def" ~= "abcdefghi".substrings`
print("Found substring: def")
case "some other potential substring":
print("Found \"some other potential substring\"")
default: print("No substring matches found")
}
Implementation:
import Foundation
public struct SubstringMatchSource {
private let wrapped: String
public init(wrapping wrapped: String) {
self.wrapped = wrapped
}
public func contains(_ substring: String) -> Bool {
return self.wrapped.contains(substring)
}
public static func ~= (substring: String, source: SubstringMatchSource) -> Bool {
return source.contains(substring)
}
}
extension String {
var substrings: SubstringMatchSource {
return SubstringMatchSource(wrapping: self)
}
}
I'd recommend using a dictionary instead, as a mapping between the substring you're searching for and the corresponding image:
func image(for weatherString: String) -> UIImage? {
let imageMapping = [
"Clear": self.soleadoImage,
"rain": self.soleadoImage,
"broken clouds": self.nubladoImage]
return imageMapping.first { weatherString.contains($0.key) }?.value
}
A dictionary gives you flexibility, adding new mappings is easy to do.
This link also describes overloading operator ~= which is actually used by the switch statement for matching cases to allow you to match regular expressions.

Converting Character in an array to an Integer

I can't seem to figure out how to do this even though I've searched through documentation.
I'm trying to figure out how to convert a character at an index in an array to an integer.
For example, say I have a character array named "container", I can't figure out how to do:
var number:Integer = container[3]
Thanks for the help!
Swift doesn't make it easy to convert between primitive and typed representations of things. Here's an extension that should help in the meantime:
extension Character {
func utf8Value() -> UInt8 {
for s in String(self).utf8 {
return s
}
return 0
}
func utf16Value() -> UInt16 {
for s in String(self).utf16 {
return s
}
return 0
}
func unicodeValue() -> UInt32 {
for s in String(self).unicodeScalars {
return s.value
}
return 0
}
}
This allows you to get pretty close to what you want:
let container : Array<Character> = [ "a", "b", "c", "d" ]
/// can't call anything here, subscripting's also broken
let number = container[2]
number.unicodeValue() /// Prints "100"
For any engineers that come across this question, see rdar://17494834
I am not sure that it is effective or not but at least it worked. I converted Character to String then to Int.
String(yourCharacterInArray).toInt()
You may try this:
var container = "$0123456789"
var number:Int = Array(container.utf8).map { Int($0) }[3]
It's totally ugly, but it does the job. Also it is a bit computational expensive (O(n) each time one access a character in a string). Still this can be a trick to get back a way to build the CStrings:
typealias CString = Array<CChar>
func toCString(string: String) -> CString {
return Array(string.utf8).map { CChar($0) } + [0]
}
var cString = toCString("$ 0123456789")
println("The 2nd character in cString has value \(cString[1])") // It outputs 32
or without implementing a function:
var container = "$ 0123456789"
var containerAsCString = Array(container.utf8).map { CChar($0) } + [0]
println("The 2nd character in container has value \(containerAsCString[1])") // It outputs 32
Why not just for loop the array and convert everything to Int?
https://developer.apple.com/Library/mac/documentation/General/Reference/SwiftStandardLibraryReference/index.html
Why not just convert the character to String, get the unicodeScalars for it and extract the .value on the scalar?
something like:
var chr: [Character] = ["C", "B", "A"]
for a in String(chr[1]).unicodeScalars {
println(a.value)}
For me worked something like:
"\(container[3])".toInt()

Resources