Swift - Format textfield for a credit card [duplicate] - ios

This question already has answers here:
Formatting a UITextField for credit card input like (xxxx xxxx xxxx xxxx)
(30 answers)
Closed 6 years ago.
I've been stuck on this for awhile now and I was wondering what is the best way to format a textfield for a credit card type format?

You can use Caishen framework.
It updates the contents of the textfield after every edit using this function :
public func formattedCardNumber(cardNumberString: String) -> String {
let regex: NSRegularExpression
let cardType = cardTypeRegister.cardTypeForNumber(Number(rawValue: cardNumberString))
do {
let groups = cardType.numberGrouping
var pattern = ""
var first = true
for group in groups {
pattern += "(\\d{1,\(group)})"
if !first {
pattern += "?"
}
first = false
}
regex = try NSRegularExpression(pattern: pattern, options: NSRegularExpressionOptions())
} catch {
fatalError("Error when creating regular expression: \(error)")
}
return NSArray(array: self.splitString(cardNumberString, withRegex: regex)).componentsJoinedByString(self.separator)
}

Related

How to remove zero width spaces from string in Swift? [duplicate]

This question already has answers here:
How to remove special characters from string in Swift 2?
(6 answers)
Closed 3 years ago.
I need to filter invisible character from a string. In the attached screen shot, string "​Cilantro" has some hidden character and when i get count of this before and after removing hidden character it shows different character count.
I just want to filter invisible characters not special characters, for example I dont want to filter á, ã è etc characters.
Note: I removed hidden characters using "delete" button.
For the reference I am adding here the String with invisible character: "​Cilantro". I am not sure if it will show at your end too.
Swift 5 or later
You can use new Character isLetter property
let del = Character(UnicodeScalar(127)!)
let string = "Cilantro\(del)\(del)"
print(string.count) // "10\n"
let filtered = string.filter { $0.isLetter }
print(filtered.count) // "8\n"
let string = "cafe\u{301}"
let filtered = string.filter { $0.isLetter }
print(filtered) // "café"
If you just want to remove zero width spaces from your string you can do as follow:
extension Character {
static let zeroWidthSpace = Self(.init(0x200B)!)
var isZeroWidthSpace: Bool { self == .zeroWidthSpace }
}
extension Bool {
var negated: Bool { !self }
}
let str = "​Cilantro"
print(str.count) // 9
let filtered = str.filter(\.isZeroWidthSpace.negated)
print(filtered.count) // 8

Get currency code / symbol from language code in iOS [duplicate]

This question already has answers here:
Get local currency in swift
(2 answers)
iPhone: How to get local currency symbol (i.e. "$" instead of "AU$")
(7 answers)
Closed 5 years ago.
In my swift project, I have to show the list of available Locale Identifiers. If user selects a locale like "ar" i.e. lanugage code alone. How I can get the currency symbols or number formats for this.
func listCountriesAndCurrencies() {
let localeIds = Locale.availableIdentifiers
var countryCurrency = [String: String]()
for localeId in localeIds {
let locale = Locale(identifier: localeId)
if let country = locale.regionCode, country.count == 2 { // how to get currency for locale without region code ?
if let currency = locale.currencySymbol {
countryCurrency[localeId] = currency
}
}
}
let sorted = countryCurrency.keys.sorted()
for country in sorted {
let currency = countryCurrency[country]!
print("country: \(country), currency: \(currency)")
}
}
My question is explained in the code comment

Comparing quantities of unique elements contained in large data sets [duplicate]

This question already has answers here:
Refactored Solution In Swift
(2 answers)
Closed 6 years ago.
I'm attempting to solve HackerRank's Hash Table Ransom Note challenge. There are 19 test cases and I'm passing all but two of time due to timeout on larger data sets (10,000-30,000 entries).
I'm given:
1) an array of words contained in a magazine and
2) an array of words for a ransom note. My objective is to determine if the words in the magazine can be used to construct a ransom note.
I need to have enough unique elements in the magazineWords to satisfy the quantity needed by noteWords.
I'm using this code to make that determination...and it takes FOREVER...
for word in noteWordsSet {
// check if there are enough unique words in magazineWords to put in the note
if magazineWords.filter({$0==word}).count < noteWords.filter({$0==word}).count {
return "No"
}
}
What is a faster way to accomplish this task?
Below is my complete code for the challenge:
import Foundation
var magazineWords = // Array of 1 to 30,000 strings
var noteWords = // Array of 1 to 30,000 strings
enum RegexString: String {
// Letters a to z, A to Z, 1 to 5 characters long
case wordCanBeUsed = "([a-zA-Z]{1,5})"
}
func matches(for regexString: String, in text: String) -> [String] {
// Hat tip MartinR for this
do {
let regex = try NSRegularExpression(pattern: regexString)
let nsString = text as NSString
let results = regex.matches(in: text, range: NSRange(location: 0, length: nsString.length))
return results.map { nsString.substring(with: $0.range)}
} catch let error {
print("invalid regex: \(error.localizedDescription)")
return []
}
}
func canCreateRansomNote(from magazineWords: [String], for noteWords: [String]) -> String {
// figure out what's unique
let magazineWordsSet = Set(magazineWords)
let noteWordsSet = Set(noteWords)
let intersectingValuesSet = magazineWordsSet.intersection(noteWordsSet)
// constraints specified in challenge
guard magazineWords.count >= 1, noteWords.count >= 1 else { return "No" }
guard magazineWords.count <= 30000, noteWords.count <= 30000 else { return "No" }
// make sure there are enough individual words to work with
guard magazineWordsSet.count >= noteWordsSet.count else { return "No" }
guard intersectingValuesSet.count == noteWordsSet.count else { return "No" }
// check if all the words can be used. assume the regex method works perfectly
guard noteWords.count == matches(for: RegexString.wordCanBeUsed.rawValue, in: noteWords.joined(separator: " ")).count else { return "No" }
// FIXME: this is a processor hog. I'm timing out when I get to this point
// need to make sure there are enough magazine words to write the note
// compare quantity of word in magazine with quantity of word in note
for word in noteWordsSet {
// check if there are enough unique words in magazineWords to put in the note
if magazineWords.filter({$0==word}).count < noteWords.filter({$0==word}).count {
return "No"
}
}
return "Yes"
}
print(canCreateRansomNote(from: magazineWords, for: noteWords))
I don't know how to read from the test case on the contest website or what frameworks you are allowed. If Foundation is allowed, you can use NSCountedSet
import Foundation
let fileContent = try! String(contentsOf: URL(fileURLWithPath: "/path/to/file.txt"))
let scanner = Scanner(string: fileContent)
var m = 0
var n = 0
scanner.scanInt(&m)
scanner.scanInt(&n)
var magazineWords = NSCountedSet(capacity: m)
var ransomWords = NSCountedSet(capacity: n)
for i in 0..<(m+n) {
var word: NSString? = nil
scanner.scanUpToCharacters(from: .whitespacesAndNewlines, into: &word)
if i < m {
magazineWords.add(word!)
} else {
ransomWords.add(word!)
}
}
var canCreate = true
for w in ransomWords {
if ransomWords.count(for: w) > magazineWords.count(for: w) {
canCreate = false
break
}
}
print(canCreate ? "Yes" : "No")
It works by going through the input file one word at a time, counting how many times that word appears in the magazine and in the ransom note. Then if any word appear more frequently in the ransom note than in the magazine, it fails the test immediately. Run the 30,000 words test case in less than 1 second on my iMac 2012.

Swift: how to censor/filter text entered for swear words, etc?

I just want to see whether there is an established way to do this, or how one would go about this.
I have a text field that essentially acts as a form in my iOs app where a user can post something. I can't have users posting swear words/inappropriate crap, so I want to filter out and display an error if the string they enter contains one of these words.
How do other apps in Swift do this? Do they just search through the string to see if it contains the word (obviously not within other words, but standing alone) or is there another method?
How can I accurately filter out the swear words from my user post in Swift?
Construct a list of words you consider to be swear words, and simply check the user entered string whether any of these words are contained within the string.
Swift 3:
import Foundation
func containsSwearWord(text: String, swearWords: [String]) -> Bool {
return swearWords
.reduce(false) { $0 || text.contains($1.lowercased()) }
}
// example usage
let listOfSwearWords = ["darn", "crap", "newb"]
/* list as lower case */
let userEnteredText1 = "This darn didelo thread is a no no."
let userEnteredText2 = "This fine didelo thread is a go."
print(containsSwearWord(text: userEnteredText1, swearWords: listOfSwearWords)) // true
print(containsSwearWord(text: userEnteredText2, swearWords: listOfSwearWords)) // false
Swift 2.2:
import Foundation
func containsSwearWord(text: String, swearWords: [String]) -> Bool {
return swearWords
.reduce(false) { $0 || text.containsString($1.lowercaseString) }
}
// example usage
let listOfSwearWords = ["darn", "crap", "newb"]
/* list as lower case */
let userEnteredText1 = "This darn didelo thread is a no no."
let userEnteredText2 = "This fine didelo thread is a go."
print(containsSwearWord(userEnteredText1, swearWords: listOfSwearWords)) // true
print(containsSwearWord(userEnteredText2, swearWords: listOfSwearWords)) // false
I created a class that enables you to feed a string in and remove profanity. Here's a link to the repo.
Here's the code:
class ProfanityFilter: NSObject {
static let sharedInstance = ProfanityFilter()
private override init() {}
// Customize as needed
private let dirtyWords = "\\b(ducker|mother ducker|motherducker|shot|bad word|another bad word|)\\b"
// Courtesy of Martin R
// https://stackoverflow.com/users/1187415/martin-r
private func matches(for regex: String, in text: String) -> [String] {
do {
let regex = try NSRegularExpression(pattern: regex, options: [.caseInsensitive])
let nsString = text as NSString
let results = regex.matches(in: text, range: NSRange(location: 0, length: nsString.length))
return results.map { nsString.substring(with: $0.range)}
} catch let error {
print("invalid regex: \(error.localizedDescription)")
return []
}
}
public func cleanUp(_ string: String) -> String {
let dirtyWords = matches(for: self.dirtyWords, in: string)
if dirtyWords.count == 0 {
return string
} else {
var newString = string
dirtyWords.forEach({ dirtyWord in
let newWord = String(repeating: "😲", count: dirtyWord.characters.count)
newString = newString.replacingOccurrences(of: dirtyWord, with: newWord, options: [.caseInsensitive])
})
return newString
}
}
}
Usage:
yourLabel.text = ProfanityFilter.sharedInstance.cleanUp(yourString)
Extension checking for foul language.
Swift 4.2
Example Usage:
"poop".containsBadWord()
Extension:
extension String {
func containsBadWord()->Bool {
//Sorry for bad words
let badWords = ["insert","bad","words","here","poop"]
for word in badWords {
if lowercased().contains(word) {
return true
}
}
return false
}
}
I would suggest looking into an API to which you can submit a string and get a JSON response containing information such as:
Is the string bad?
Total # of bad words contained in string
An array containing all recognized bad words
A censored version of the input string
I found a couple sources via Google. Check these out and do a little more research to find if an API is the best fit for you and which one you should use. I would assume that using an API like the one I have listed below would be the most practical approach, as you would NOT have to compile a list of "bad" words yourself and use resources from the device to sort through the list (which can contain thousands of words).
Rather, you can simply submit a string using the API to get a network response containing the data in JSON format from the API server.
Why not let the API Server do the logic for you and just spit out an answer?
NeutrinoAPI
If this method returns a range,
str.range(of: "darn|crap|newb", options: [.regularExpressionSearch, .caseInsensitiveSearch], range: str.startIndex..<str.endIndex, locale:nil)
an offensive word has been found. While this method can be used to remove the offending strings:
str.replacingOccurrences(of: "darn|crap|newb", with: "", options: [.regularExpressionSearch, .caseInsensitiveSearch])
If you filter bad words locally you wouldn’t easily accommodate many languages, also as new bad words appear, you would have to waste a developers time manually putting in bad words, alternatively, there are apis designed for this purpose: https://www.moderatecontent.com/documentation/badwords

Swift Checking if entire word is present in a string [duplicate]

This question already has answers here:
Detect whole word in NSStrings
(4 answers)
Closed 6 years ago.
What I want to do is to check if an entire word is present in a string. Let me give you an example.
let mainString = "this is a my string"
let searchString = "str"
if mainString.containsString(searchString) {
}
Here this condition will be true but I do not want this. I want it to be true when either "this" or "is" or "a" or "my" or "string" is searched in the mainString meaning I want to compare the whole word not the characters within the string. I hope I have elaborated it.
// The following method will return a string without punctuation and non-required stuff characters
Source of information : How to remove special characters from string in Swift 2?
func removeSpecialCharsFromString(mainString) -> String {
let okayChars : Set<Character> =
Set("abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLKMNOPQRSTUVWXYZ".characters)
return String(text.characters.filter {okayChars.contains($0) })
}
let stringWithoutSpecialChars = removeSpecialCharsFromString(mainString)
// Source of info : Chris's answer on this page
let components = stringWithoutSpecialChars.componentsSeparatedByString(" ")
for component in components {
print(component)
}
You have to use a Regex like that :
NSString *pattern = #"\\str\\b";
NSRange range = [text rangeOfString:pattern options:NSRegularExpressionSearch|NSCaseInsensitiveSearch];
The \b at the end of the pattern do what you want, it will match only whole words.
I would recommend splitting your string into components and seeing if a component matches your string. Below is a method that uses components to check if any word matches a given search term.
func isTermInString(term:String, stringToSearch:String) -> Bool {
let components = stringToSearch.componentsSeparatedByString(" ")
for component in components {
if component == term {
return true
}
}
return false
}

Resources