In swift how do I see if a specific character is present in a UITextField? - swift

Firstly, apologies - new to all this.
I am trying to take whatever text a user has inputted to a UITextField and see if it contains a certain letter, then count the number of times that letter has been entered.
So for example, if the string was "Hello" I would want it to return, as a score if like, that there are two l's. I don't want it to be case sensitive.
Thanks!

You can use try this extension:
extension String
{
func numberOfChars(char:Character) -> Int
{
var counter = 0
for chr in self
{
if chr == char
{
counter++
}
}
return counter
}
}
And then use it like:
println(textField.text.numberOfChars(Character("a")))

To check when the user has entered text in your UITextField you can use: addObserver to the UITextField and create a method using observeValueForKeyPath. In this method you can use to count the number of characters:
let someString = "Hello"
let count = Array(someString).map { $0 == "l" }.filter { $0 == true }.count
To use an extension like Dejan Skledar suggested:
extension String {
func numberOfChars(char: Character) -> Int {
return Array(someString).map { $0 == "l" }.filter { $0 == true }.count
}
}
and use it like:
println(textField.text.numberOfChars("l") // prints "3"

Related

How to check the string doesn’t contain any letters in swift?

i have trouble during making the letter checker, my code is like this: if !containLetters(“1234h”){print(“pass”)}
my function is
func containsOnlyNum(input: String) -> Bool {
var ok = false
for chr in input {
for check in "1234567890.-"{
if chr == check{
ok = true
}
}
if ok != true{
return false
}
}
return true
}
If I check for “h” then didn’t pass, but if i check for ”1h” then it still pass! Please help me to fix this problem. I will give a big thank for anyone who helped me
The simplest way to fix the algorithm is this way:
func containsOnlyNum(input: String) -> Bool {
// check every character
for chr in input {
var isNum = false
for check in "1234567890.-"{
if chr == check {
isNum = true
// if we have found a valid one, we can break the iteration
break
}
}
if !isNum {
return false
}
}
return true
}
print(containsOnlyNum(input: "1234")) // true
print(containsOnlyNum(input: "1234h")) // false
However, then you can directly simplify it to:
func containsOnlyNum(input: String) -> Bool {
return input.allSatisfy { chr in
"1234567890.-".contains(chr)
}
}
which does exatly the same but uses allSatisfy and contains functions, which represent the logical operators ALL and EXISTS.
However, programmers normally use regular expressions for similar tasks:
func containsOnlyNum(input: String) -> Bool {
return input.range(of: "^[0-9.\\-]+$", options: .regularExpression) != nil
}
You can check that a string contains only the characters you're interested in like this:
extension String {
var containsOnlyNum: Bool {
let wanted = CharacterSet.decimalDigits
.union(CharacterSet(charactersIn: "-."))
return unicodeScalars
.allSatisfy(wanted.contains)
}
}
"-12.34".containsOnlyNum // true
"A1234".containsOnlyNum // false
But if you are interested in numbers, then this is a problem:
"-12.-34.".containsOnlyNum // true
Instead, you can just try casting the string to a double and see if it is a number or not
Double("1234") != nil // true, a number
Double("-1.234") != nil // true, a number
Double("A1234") != nil // false, not a number
Double("-12.-34.") != nil // false, not a number
Which is almost right unless you don't want this case:
Double("1234e2") != nil // true, a number
But you can use both checks if you don't want to allow that, or else if you are able to parse a Double from the input you can just do the cast.

Dictionary in Dictionary value search

I am downloading information from a Firebase database and it is being inputted via a for loop into:
static var Reports = [String:[String:String]]()
I need to figure out a way to search the inside values for a certain string
I have messed around with this but can't seem to get it inside the inside dictionary (If that makes sense)
for values in Reports.count {
if let item = Reports["favorite drink"] {
print(item)
}
}
I need to have a search string then a number of times the value appears like so:
func findString(dict Dictionary) -> Int {
var ReportsLevel1 = 0
(for loop I'm guessing)
search here for string
return ReportsLevel1
}
Tip: the outside dictionary keys are not set in stone, they depend on what time and date the report was submitted
To find out the numberOfTimes in which "yourSearchString" appears you can do as follows
var numberOfTimes = 0
for internalDictionary in reports.values
{
for value in internalDictionary.values
{
if (value == "yourSearchString") { numberOfTimes += 1 }
}
}
or
let numberOfTimes = reports.flatMap { internalDictsArray in internalDictsArray.value.filter { $0.value == "yourSearchString" } }.count

How can I check if a string contains letters in Swift? [duplicate]

This question already has answers here:
What is the best way to determine if a string contains a character from a set in Swift
(11 answers)
Closed 7 years ago.
I'm trying to check whether a specific string contains letters or not.
So far I've come across NSCharacterSet.letterCharacterSet() as a set of letters, but I'm having trouble checking whether a character in that set is in the given string. When I use this code, I get an error stating:
'Character' is not convertible to 'unichar'
For the following code:
for chr in input{
if letterSet.characterIsMember(chr){
return "Woah, chill out!"
}
}
You can use NSCharacterSet in the following way :
let letters = NSCharacterSet.letters
let phrase = "Test case"
let range = phrase.rangeOfCharacter(from: characterSet)
// range will be nil if no letters is found
if let test = range {
println("letters found")
}
else {
println("letters not found")
}
Or you can do this too :
func containsOnlyLetters(input: String) -> Bool {
for chr in input {
if (!(chr >= "a" && chr <= "z") && !(chr >= "A" && chr <= "Z") ) {
return false
}
}
return true
}
In Swift 2:
func containsOnlyLetters(input: String) -> Bool {
for chr in input.characters {
if (!(chr >= "a" && chr <= "z") && !(chr >= "A" && chr <= "Z") ) {
return false
}
}
return true
}
It's up to you, choose a way. I hope this help you.
You should use the Strings built in range functions with NSCharacterSet rather than roll your own solution. This will give you a lot more flexibility too (like case insensitive search if you so desire).
let str = "Hey this is a string"
let characterSet = NSCharacterSet(charactersInString: "aeiou")
if let _ = str.rangeOfCharacterFromSet(characterSet, options: .CaseInsensitiveSearch) {
println("true")
}
else {
println("false")
}
Substitute "aeiou" with whatever letters you're looking for.
A less flexible, but fun swift note all the same, is that you can use any of the functions available for Sequences. So you can do this:
contains("abc", "c")
This of course will only work for individual characters, and is not flexible and not recommended.
The trouble with .characterIsMember is that it takes a unichar (a typealias for UInt16).
If you iterate your input using the utf16 view of the string, it will work:
let set = NSCharacterSet.letterCharacterSet()
for chr in input.utf16 {
if set.characterIsMember(chr) {
println("\(chr) is a letter")
}
}
You can also skip the loop and use the contains algorithm if you only want to check for presence/non-presence:
if contains(input.utf16, { set.characterIsMember($0) }) {
println("contains letters")
}

Check empty string in Swift?

In Objective C, one could do the following to check for strings:
if ([myString isEqualToString:#""]) {
NSLog(#"myString IS empty!");
} else {
NSLog(#"myString IS NOT empty, it is: %#", myString);
}
How does one detect empty strings in Swift?
There is now the built in ability to detect empty string with .isEmpty:
if emptyString.isEmpty {
print("Nothing to see here")
}
Apple Pre-release documentation: "Strings and Characters".
A concise way to check if the string is nil or empty would be:
var myString: String? = nil
if (myString ?? "").isEmpty {
print("String is nil or empty")
}
I am completely rewriting my answer (again). This time it is because I have become a fan of the guard statement and early return. It makes for much cleaner code.
Non-Optional String
Check for zero length.
let myString: String = ""
if myString.isEmpty {
print("String is empty.")
return // or break, continue, throw
}
// myString is not empty (if this point is reached)
print(myString)
If the if statement passes, then you can safely use the string knowing that it isn't empty. If it is empty then the function will return early and nothing after it matters.
Optional String
Check for nil or zero length.
let myOptionalString: String? = nil
guard let myString = myOptionalString, !myString.isEmpty else {
print("String is nil or empty.")
return // or break, continue, throw
}
// myString is neither nil nor empty (if this point is reached)
print(myString)
This unwraps the optional and checks that it isn't empty at the same time. After passing the guard statement, you can safely use your unwrapped nonempty string.
In Xcode 11.3 swift 5.2 and later
Use
var isEmpty: Bool { get }
Example
let lang = "Swift 5"
if lang.isEmpty {
print("Empty string")
}
If you want to ignore white spaces
if lang.trimmingCharacters(in: .whitespaces).isEmpty {
print("Empty string")
}
Here is how I check if string is blank. By 'blank' I mean a string that is either empty or contains only space/newline characters.
struct MyString {
static func blank(text: String) -> Bool {
let trimmed = text.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines)
return trimmed.isEmpty
}
}
How to use:
MyString.blank(" ") // true
You can also use an optional extension so you don't have to worry about unwrapping or using == true:
extension String {
var isBlank: Bool {
return self.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty
}
}
extension Optional where Wrapped == String {
var isBlank: Bool {
if let unwrapped = self {
return unwrapped.isBlank
} else {
return true
}
}
}
Note: when calling this on an optional, make sure not to use ? or else it will still require unwrapping.
To do the nil check and length simultaneously
Swift 2.0 and iOS 9 onwards you could use
if(yourString?.characters.count > 0){}
isEmpty will do as you think it will, if string == "", it'll return true.
Some of the other answers point to a situation where you have an optional string.
PLEASE use Optional Chaining!!!!
If the string is not nil, isEmpty will be used, otherwise it will not.
Below, the optionalString will NOT be set because the string is nil
let optionalString: String? = nil
if optionalString?.isEmpty == true {
optionalString = "Lorem ipsum dolor sit amet"
}
Obviously you wouldn't use the above code. The gains come from JSON parsing or other such situations where you either have a value or not. This guarantees code will be run if there is a value.
Check check for only spaces and newlines characters in text
extension String
{
var isBlank:Bool {
return self.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet()).isEmpty
}
}
using
if text.isBlank
{
//text is blank do smth
}
Swift String (isEmpty vs count)
You should use .isEmpty instead of .count
.isEmpty Complexity = O(1)
.count Complexity = O(n)
isEmpty does not use .count under the hood, it compares start and end indexes startIndex == endIndex
Official doc Collection.count
Complexity: O(1) if the collection conforms to RandomAccessCollection; otherwise, O(n), where n is the length of the collection.
Single character can be represented by many combinations of Unicode scalar values(different memory footprint), that is why to calculate count we should iterate all Unicode scalar values
String = alex
String = \u{61}\u{6c}\u{65}\u{78}
[Char] = [a, l, e, x]
Unicode text = alex
Unicode scalar values(UTF-32) = u+00000061u+0000006cu+00000065u+00000078
1 Character == 1 extended grapheme cluster == set of Unicode scalar values
Example
//Char á == extended grapheme cluster of Unicode scalar values \u{E1}
//Char á == extended grapheme cluster of Unicode scalar values \u{61}\u{301}
let a1: String = "\u{E1}" // Unicode text = á, UTF-16 = \u00e1, UTF-32 = u+000000e1
print("count:\(a1.count)") //count:1
// Unicode text = a, UTF-16 = \u0061, UTF-32 = u+00000061
// Unicode text = ́, UTF-16 = \u0301, UTF-32 = u+00000301
let a2: String = "\u{61}\u{301}" // Unicode text = á, UTF-16 = \u0061\u0301, UTF-32 = u+00000061u+00000301
print("count:\(a2.count)") //count:1
For optional Strings how about:
if let string = string where !string.isEmpty
{
print(string)
}
if myString?.startIndex != myString?.endIndex {}
I can recommend add small extension to String or Array that looks like
extension Collection {
public var isNotEmpty: Bool {
return !self.isEmpty
}
}
With it you can write code that is easier to read.
Compare this two lines
if !someObject.someParam.someSubParam.someString.isEmpty {}
and
if someObject.someParam.someSubParam.someString.isNotEmpty {}
It is easy to miss ! sign in the beginning of fist line.
public extension Swift.Optional {
func nonEmptyValue<T>(fallback: T) -> T {
if let stringValue = self as? String, stringValue.isEmpty {
return fallback
}
if let value = self as? T {
return value
} else {
return fallback
}
}
}
What about
if let notEmptyString = optionalString where !notEmptyString.isEmpty {
// do something with emptyString
NSLog("Non-empty string is %#", notEmptyString)
} else {
// empty or nil string
NSLog("Empty or nil string")
}
You can use this extension:
extension String {
static func isNilOrEmpty(string: String?) -> Bool {
guard let value = string else { return true }
return value.trimmingCharacters(in: .whitespaces).isEmpty
}
}
and then use it like this:
let isMyStringEmptyOrNil = String.isNilOrEmpty(string: myString)

What's the best way to convert String into [Character] in Swift?

I would like to run a filter on a string. My first attempt failed as string is not automagically converted to Character[].
var s: String = "abc"
s.filter { $0 != "b" }
If I clumsily convert the String to Character[] with following code, it works as expected. But surely there has to be a neater way?
var cs:Character[] = []
for c in s {
cs = cs + [c]
}
cs = cs.filter { $0 != "b" }
println(cs)
String conforms to the CollectionType protocol, so you can pass it directly to the function forms of map and filter without converting it at all:
let cs = filter(s) { $0 != "f" }
cs here is an Array of Characters. You can turn it into a String by using the String(seq:) initializer, which constructs a String from any SequenceType of Characters. (SequenceType is a protocol that all lists conform to; for loops use them, among many other things.)
let filteredString = String(seq: cs)
Of course, you can just as easily put those two things in one statement:
let filteredString = String(seq: filter(s) { $0 != "f" })
Or, if you want to make a convenience filter method like the one on Array, you can use an extension:
extension String {
func filter(includeElement: Character -> Bool) -> String {
return String(seq: Swift.filter(self, includeElement))
}
}
(You write it "Swift.filter" so the compiler doesn't think you're trying to recursively call the filter method you're currently writing.)
As long as we're hiding how the filtering is performed, we might as well use a lazy filter, which should avoid constructing the temporary array at all:
extension String {
func filter(includeElement: Character -> Bool) -> String {
return String(seq: lazy(self).filter(includeElement))
}
}
I don't know of a built in way to do it, but you could write your own filter method for String:
extension String {
func filter(f: (Character) -> Bool) -> String {
var ret = ""
for character in self {
if (f(character)) {
ret += character
}
}
return ret
}
}
If you don't want to use an extension you could do this:
Array(s).filter({ $0 != "b" }).reduce("", combine: +)
You can use this syntax:
var chars = Character[]("abc")
I'm not 100% sure if the result is an array of Characters or not but works for my use case.
var str = "abc"
var chars = Character[](str)
var result = chars.map { char in "char is \(char)" }
result
The easiest way to convert a char to string is using the backslash (), for example I have a function to reverse a string, like so.
var identityNumber:String = id
for char in identityNumber{
reversedString = "\(char)" + reversedString
}