I want to get only first letter from last name for privacy of users. Example: "John D."
extension String
{
public func getAcronyms(separator: String = "") -> String
{
let acronyms = self.components(separatedBy: " ").map({ String($0.characters.first!) }).joined(separator: separator);
return acronyms;
}
}
For proper naming, you have to use PersonNameComponentsFormatter.
let name = "Joe Singh"
let nameFormatter = PersonNameComponentsFormatter()
if let nameComps = nameFormatter.personNameComponents(from: name), let firstLetter = nameComps.givenName?.first, let lastName = nameComps.familyName {
let sortName = "\(firstLetter). \(lastName)" // J. Singh
}
You can also find:
nameComps.middleName
nameComps.familyName
nameComps.nameSuffix
nameComps.namePrefix
And also can configured the format of your names
Default
short
long
abbreviated
Related
I am using multiline string as follows. there is a line where I display submittedPerson, either can be his Id or email, but also can be nil as well. I wonder how do you hide this line if it returns nil
var submittedPerson = ""
if let Id = User[index].Id {
submittedPerson = Id
} else if let email = User[index].email {
submittedPerson = email
}
let displayStr = """
\(department)
\"submittedBy" : \(submittedPerson)
\(submittedDate)
"""
I'll assume the hidden requirement here is that you still want to keep the multiline string literal readable, and not have code duplication :)
One way you could do this is to move one of the two line feed characters to when you assign to submittedPerson:
var submittedPerson: String? = ""
if let Id = User[index].Id {
submittedPerson = "\n\(Id)\n" // note the lines feeds
} else if let email = User[index].email {
submittedPerson = "\n\(email)\n"
}
let displayStr = """
\(department)
\(submittedPerson ?? "")
\(submittedDate)
"""
Say I have a String, how do I determine the number of words in it? I'm trying to create an extension like:
extension String {
var numberOfWords: Int {
// Insert string-counting code here
}
}
If you search "word count string swift" you'll find dozens of StackOverflow answers and gists that tell you to split the string using str.components(separatedBy: " ").count.
DON'T USE components(separatedBy:)!!!
Many non-European languages (particularly East Asian languages) don't use spaces to split words. This will also incorrectly count hyphenated words as separate, and lone punctuation as a word.
The most correct AND most performant way to solve this problem is to use either enumerateSubstrings(in:options:) or CFStringTokenizer.
// enumerateSubstrings
extension String {
var numberOfWords: Int {
var count = 0
let range = startIndex..<endIndex
enumerateSubstrings(in: range, options: [.byWords, .substringNotRequired, .localized], { _, _, _, _ -> () in
count += 1
})
return count
}
}
OR:
// CFStringTokenizer
extension String {
var numberOfWords: Int {
let inputRange = CFRangeMake(0, utf16.count)
let flag = UInt(kCFStringTokenizerUnitWord)
let locale = CFLocaleCopyCurrent()
let tokenizer = CFStringTokenizerCreate(kCFAllocatorDefault, self as CFString, inputRange, flag, locale)
var tokenType = CFStringTokenizerAdvanceToNextToken(tokenizer)
var count = 0
while tokenType != [] {
count += 1
tokenType = CFStringTokenizerAdvanceToNextToken(tokenizer)
}
return count
}
}
Both are very performant, but enumerateSubtrings(in:options:...) is about twice as fast.
Shocked that nobody is pointing this out elsewhere, so I hope people searching for a solution find this.
Count of words in a string
Create an extension of String
extension String{
var wordCount:Int{
let chararacter = CharacterSet.whitespacesAndNewlines.union(.punctuationCharacters)
let comps = components(separatedBy: chararacter)
let words = comps.filter { !$0.isEmpty }
return words.count
}
}
How to use
"This is a test string".wordCount // Result: 5
I want to get a substring out of a string which starts with either "<ONLINE>" or "<OFFLINE>" (which should become my substring). When I try to create a Range object, I can easily access the the first character by using startIndex but how do I get the index of the closing bracket of my substring which will be either the 8th or 9th character of the full string?
UPDATE:
A simple example:
let onlineString:String = "<ONLINE> Message with online tag!"
let substring:String = // Get the "<ONLINE> " part from my string?
let onlineStringWithoutTag:String = onlineString.replaceOccurances(of: substring, with: "")
// What I should get as the result: "Message with online tag!"
So basically, the question is: what do I do for substring?
let name = "Ajay"
// Use following line to extract first chracter(In String format)
print(name.characters.first?.description ?? "");
// Output : "A"
If you did not want to use range
let onlineString:String = "<ONLINE> Message with online tag!"
let substring:String = onlineString.components(separatedBy: " ")[0]
print(substring) // <ONLINE>
The correct way would be to use indexes as following:
let string = "123 456"
let firstCharIndex = string.index(string.startIndex, offsetBy: 1)
let firstChar = string.substring(to: firstCharIndex)
print(firstChar)
This Code provides you the first character of the string.
Swift provides this method which returns character? you have to wrap it before use
let str = "FirstCharacter"
print(str.first!)
Similar to OOPer's:
let string = "<ONLINE>"
let closingTag = CharacterSet(charactersIn: ">")
if let closingTagIndex = string.rangeOfCharacter(from: closingTag) {
let mySubstring = string.substring(with: string.startIndex..<closingTagIndex.upperBound)
}
Or with regex:
let string = "<ONLINE>jhkjhkh>"
if let range = string.range(of: "<[A-Z]+>", options: .regularExpression) {
let mySubstring = string.substring(with: range)
}
This code be some help for your purpose:
let myString = "<ONLINE>abc"
if let rangeOfClosingAngleBracket = myString.range(of: ">") {
let substring = myString.substring(to: rangeOfClosingAngleBracket.upperBound)
print(substring) //-><ONLINE>
}
Swift 4
let firstCharIndex = oneGivenName.index(oneGivenName.startIndex, offsetBy: 1)
let firstChar = String(oneGivenName[..<firstCharIndex])
let character = MyString.first
it's an simple way to get first character from string in swift.
In swift 5
let someString = "Stackoverflow"
let firstChar = someString.first?.description ?? ""
print(firstChar)
Swift 5 extension
extension String {
var firstCharactor: String? {
guard self.count > 0 else {
return nil
}
return String(self.prefix(1))
}
}
a string such as ! !! yuahl! ! , I want delete ! and , when I code like this
for index in InputName.characters.indices {
if String(InputName[index]) == "" || InputName.substringToIndex(index) == "!" {
InputName.removeAtIndex(index)
}
}
have this error " fatal error: subscript: subRange extends past String end ", how should I do? THX :D
Swift 5+
let myString = "aaaaaaaabbbb"
let replaced = myString.replacingOccurrences(of: "bbbb", with: "") // "aaaaaaaa"
If you need to remove characters only on both ends, you can use stringByTrimmingCharactersInSet(_:)
let delCharSet = NSCharacterSet(charactersInString: "! ")
let s1 = "! aString! !"
let s1Del = s1.stringByTrimmingCharactersInSet(delCharSet)
print(s1Del) //->aString
let s2 = "! anotherString !! aString! !"
let s2Del = s2.stringByTrimmingCharactersInSet(delCharSet)
print(s2Del) //->anotherString !! aString
If you need to remove characters also in the middle, "reconstruct from the filtered output" would be a little bit more efficient than repeating single character removal.
var tempUSView = String.UnicodeScalarView()
tempUSView.appendContentsOf(s2.unicodeScalars.lazy.filter{!delCharSet.longCharacterIsMember($0.value)})
let s2DelAll = String(tempUSView)
print(s2DelAll) //->anotherStringaString
If you don't mind generating many intermediate Strings and Arrays, this single liner can generate the expected output:
let s2DelAll2 = s2.componentsSeparatedByCharactersInSet(delCharSet).joinWithSeparator("")
print(s2DelAll2) //->anotherStringaString
I find that the filter method is a good way to go for this sort of thing:
let unfiltered = "! !! yuahl! !"
// Array of Characters to remove
let removal: [Character] = ["!"," "]
// turn the string into an Array
let unfilteredCharacters = unfiltered.characters
// return an Array without the removal Characters
let filteredCharacters = unfilteredCharacters.filter { !removal.contains($0) }
// build a String with the filtered Array
let filtered = String(filteredCharacters)
print(filtered) // => "yeah"
// combined to a single line
print(String(unfiltered.characters.filter { !removal.contains($0) })) // => "yuahl"
Swift 3
In Swift 3, the syntax is a bit nicer. As a result of the Great Swiftification of the old APIs, the factory method is now called trimmingCharacters(in:). Also, you can construct the CharacterSet as a Set of single-character Strings:
let string = "! !! yuahl! !"
string.trimmingCharacters(in: [" ", "!"]) // "yuahl"
If you have characters in the middle of the string you would like to remove as well, you can use components(separatedBy:).joined():
let string = "! !! yu !ahl! !"
string.components(separatedBy: ["!", " "]).joined() // "yuahl"
H/T #OOPer for the Swift 2 version
func trimLast(character chars: Set<Character>) -> String {
let str: String = String(self.reversed())
guard let index = str.index(where: {!chars.contains($0)}) else {
return self
}
return String((str[index..<str.endIndex]).reversed())
}
Note:
By adding this function in String extension, you can delete the specific character of string at last.
for index in InputName.characters.indices.reversed() {
if String(InputName[index]) == "" || InputName.substringToIndex(index) == "!" {
InputName.removeAtIndex(index)
}
}
Also you can add such very helpful extension :
import Foundation
extension String{
func exclude(find:String) -> String {
return stringByReplacingOccurrencesOfString(find, withString: "", options: .CaseInsensitiveSearch, range: nil)
}
func replaceAll(find:String, with:String) -> String {
return stringByReplacingOccurrencesOfString(find, withString: with, options: .CaseInsensitiveSearch, range: nil)
}
}
you can use this:
for example if you want to remove "%" the percent from 10%
if let i = text.firstIndex(of: "%") {
text.remove(at: i) //10
}
I'm compartmentalizing users on firebase according to their email domain. What universal code can I use to extract only 'havard' in the following examples? All user emails end in '.edu'
let email = jsmith#student.havard.edu ,
let email = jsmith#havard.edu
Here is a simple function that will work for the input set you provided.
func getMainPart(s: String) -> String {
let charSet = NSCharacterSet(charactersInString: ".#")
let v = s.componentsSeparatedByCharactersInSet(charSet)
let pos = v.count - 2
return v[pos]
}
Here's another solution:
func getMainPart2(s: String) -> String {
var v = s.componentsSeparatedByString("#").last?.componentsSeparatedByString(".")
v?.removeLast()
return (v!.last)!
}
You can call it like this:
let email1 = "smith#harvard.edu"
let s = getMainPart2(email1)
print(s) // this outputs: harvard
One legal email address has only one "#" so separate email address:
public func componentsSeparatedByString(separator: String) -> [String]
This is sample code:
let components = email.componentsSeparatedByString("#").last?.componentsSeparatedByString(".")
if let index = components?.endIndex.advancedBy(-2) {
components![index]
}