Hallo katten en poesjes, Leo hier. Today’s topic is how to parse person name with Swift and how to do iOS automatically stores parts of the name for you.
Today we will explore the PersonNameComponents
API from the foundation. From time to time we are asked to parse a person’s came into our apps. There are plenty of reasons for that: you need to show just the suffix of the name, you only want to put in the header of a screen the surname of the user, you may need to send to the backend in different fields the different parts of the name, etc.
Good for us that Apple made an API ready to do that for us. Let’s explore this API and see tips and tricks about the PersonNameComponents
.
Let’s code! But first…
Painting of The Day
This painting is a 1850 portrait of Dom Pedro II from António de Souza Lobo. He was a Brazilian artist who was born in 1840. The maker’s first piece to be offered at auction was A portrait of King Pedro IV of Portugal at Veritas Art Auctioneers in 2021 The artist died in 1909.
I chose this painting because as we are talking about names, Dom Pedro ll had a giant name. The full name was: Pedro de Alcântara João Carlos Leopoldo Salvador Bibiano Francisco Xavier de Paula Leocádio Miguel Gabriel Rafael Gonzaga de Bragança e Bourbon. Imagine parsing this into your apps.
The Problem – Parse Person Name with Swift
The user inputs his/her name into an UITextField and now you have to parse/split that name into parts so you can show in other screen just the surname or the given name.
Let’s start in the beginning. How can we initialize the PersonNameComponents
.
PersonNameComponents Initialisers
We have three ways to do so. The first one is letting Swift parse everything for us:
let name = "John Lennon" var nameComponents = try PersonNameComponents(name) print(nameComponents)
Pay attention that if you use this initializer, it throws errors. So you will have to handle them if something wrong occurs in the automatic parsing.
Resulting in:
This seems right to me, isn’t it?
Second Initializer
But If you already have the specific part of the name and know where it will fit in the PersonNameComponents
, we have another option for you. I think this second initializer can be suitable for most form input cases, where you have a UITextField
for a given name, another text field for the middle name, and another one for the surname. You can use this initializer:
let name = "John Lennon" var nameComponents = PersonNameComponents(namePrefix: nil, givenName: name, middleName: nil, familyName: nil, nameSuffix: nil, nickname: nil) print(nameComponents)
Now the call does not throw anymore, and as we put the name exactly as the given name, the result will be:
Third Initializer
The third initializer useful initializer is when you have complex rules to parse names. This way you have to create your own set of parsing rules. To do that we have to make it in two steps: first, create the ParseStrategy which is a handy iOS 15 Swift protocol to parse anything into other things, and then pass it to the PersonNameComponents
to see the magic happens.
The new iOS 15 ParseStrategy
protocol is very handy for parsing a representation of a given data type, let’s take a look at it first:
/// A type that can parse a representation of a given data type. @available(macOS 12.0, iOS 15.0, tvOS 15.0, watchOS 8.0, *) public protocol ParseStrategy : Decodable, Encodable, Hashable { /// The type of the representation describing the data. associatedtype ParseInput /// The type of the data type. associatedtype ParseOutput /// Creates an instance of the `ParseOutput` type from `value`. func parse(_ value: Self.ParseInput) throws -> Self.ParseOutput }
Now let’s implement that for our use case. For our example imagine that encrypted names will be inserted, for the sake of simplicity I won’t implement a full cryptography system but think that the `decryptName` function could be a LOT more complex:
struct NameParser: ParseStrategy { var defaultPersonName = PersonNameComponents(givenName: "John", familyName: "Doe") func parse(_ value: String) throws -> PersonNameComponents { guard let intValue = Int(value) else { return defaultPersonName } return try decryptName(intValue) } private func decryptName(_ value: Int) throws -> PersonNameComponents { switch value { case 1: return try PersonNameComponents("Lola Pa Loza") case 2: return try PersonNameComponents("Moon Lighter Fuz") case 3...7: return try PersonNameComponents("Hing Chong Lau") default: return defaultPersonName } } }
Now you have to use the `NameParser` struct that conforms to ParseStrategy
to decode names, like this:
let name = "1" var nameComponents = try PersonNameComponents(name, strategy: NameParser()) print(nameComponents)
Resulting:
One curious thing you can do is use the name parse function to map things. As their function requirements are the same, we can map them directly:
print(try ["1","2","3","8"].map(nameParser.parse(_:)))
With the expected result:
Exploring the PersonNameComponents API
The PersonNameComponents automatic parser is very powerful. It can also detect name prefixes and suffixes. Look at the example below:
let name = "Mr. John Lennon Da Silva, Ph.D." var nameComponents = try PersonNameComponents(name) print(nameComponents)
Resulting:
Adding Nicknames
With PersonNameComponents
API you can also add a nickname to it:
let name = "Mr. John Lennon Da Silva, Ph.D." var nameComponents = try PersonNameComponents(name) nameComponents.nickname = "Papy Jon" print(nameComponents)
And the object will look like this:
Adding Phonetic Representation
The PersonNameComponents
API also provides you a property where you can set the phonetic representation of a name. This property is also a PersonNameComponents
.
This is important to increase the accessibility of your apps. Imagine that you have a text-to-speech tool and it has to say the person’s name. You can use phonetic representation to approximate the result for the user:
let name = "Mr. John Lennon Da Silva, Ph.D." var nameComponents = try PersonNameComponents(name) nameComponents.phoneticRepresentation = try PersonNameComponents("Mister Joonni Leenun The Silva") print(nameComponents)
Adding Name Styles
The last but not least thing you can do is to apply an automatic style to your names. With this tool you can generate name initials or just the first name, you can crop prefixes and suffixes.
Let’s see that in practice:
let name = "Mr. John Lennon Da Silva, Ph.D." var nameComponents = try PersonNameComponents(name) print(nameComponents.formatted(.name(style: .abbreviated))," - abbreviated \n") print(nameComponents.formatted(.name(style: .short))," - short \n") print(nameComponents.formatted(.name(style: .medium))," - medium \n") print(nameComponents.formatted(.name(style: .long))," - long \n")
Result in this:
Summary – Parse Person Name with Swift
Apple gives to us a lot of great tools. Today we see how simple our life can be using one of them to automatically parse names. If you ever needed to parse person name with Swift, now you know you could have used the Foundation Framework to help you!
That’s all my people, I hope you liked reading this article as much as I enjoyed writing it. If you want to support this blog you can Buy Me a Coffee or leave a comment saying hello. You can also sponsor posts and I’m open to freelance writing!
You can reach me on LinkedIn or Twitter and send me an e-mail through the contact page.
Thanks for reading and… That’s all folks.
Credits: