A first look at the Natural Language framework
Basics article available: StringsWelcome to the first Daily WWDC Update - a week-long series of daily articles, in which we'll take a first look at some of the new cool APIs and frameworks that Apple are introducing during this year's WWDC conference.
To kick things off, let's try out an exciting new cross-platform framework called Natural Language. It provides a high-level API enabling easy access to a suite of language detection features when working with text in an app.
What does the API of this new framework look like, and what could it be used for? Let's take it for a spin!
Language detection
Let's say we're building a social networking app and we want to be able to show what language a certain post or comment was written in. Normally, this is something that would require either crude guesswork or sophisticated machine learning models - but now, with Natural Language, it's as easy as asking NLLanguageRecognizer
to detect the dominant language in a given string:
let englishText = "Hello, how are you?"
let swedishText = "Hej, hur är läget?"
let spanishText = "¿Hola, como estás?"
let english = NLLanguageRecognizer.dominantLanguage(for: englishText)
let swedish = NLLanguageRecognizer.dominantLanguage(for: swedishText)
let spanish = NLLanguageRecognizer.dominantLanguage(for: spanishText)
The cool thing is that it even seems to work really well for strings that contain multiple languages. For example, here we have a string that contains both English and Swedish, with English being the dominant language - which is correctly detected by NLLanguageRecognizer
:
let mixedText = "Jag heter John, and I'm an iOS Developer from Sweden"
let language = NLLanguageRecognizer.dominantLanguage(for: mixedText)
print(language) // NLLanguage.english
Tokenizing
Another feature that Natural Language provides is the ability to tokenize a string into components - or tokens. This could come very much in handy if an app we're working on includes some kind of text composer, and we want to be able to display some quick stats - like the word or sentence count.
Tokenization is done using the NLTokenizer
class, which provides a few different units for splitting a string up into tokens - like sentence
, word
and paragraph
. Here we're detecting how many words a given string contains, and then displaying that word count using a label:
let text = "Hello, I'm pretty excited about Natural Language!"
let tokenizer = NLTokenizer(unit: .word)
tokenizer.setLanguage(.english)
tokenizer.string = text
let tokens = tokenizer.tokens(for: text.startIndex..<text.endIndex)
wordCountLabel.text = "You have typed \(tokens.count) words"
Our wordCountLabel
will in this case say "You have typed 7 words".
Detecting names of people and places
Perhaps the coolest feature of the new Natural Language framework is how it can easily detect names of people, places and organizations in a string. This could end up being super useful in order to add intelligent predictions and suggestions to many kinds of apps.
Perhaps we're building a messaging app, and we want to be able to detect names of people and match them against the user's contacts in order to make those names interactive? Or perhaps we want to detect names of places and offer to look up directions? There are loads of possibilities here, and the API seems to be both very powerful and easy to customize.
To detect names and places in a string, we'll use the NLTagger
class with the nameType
scheme. We'll then ask it to detect all tags in a given string, using a set of options that minimize "noisy" tags such as punctuation
and whitespace
, like this:
let text = "Hello, my name is John Sundell and I live in Kraków"
let tagger = NLTagger(tagSchemes: [.nameType])
tagger.string = text
let tags = tagger.tags(
in: text.startIndex..<text.endIndex,
unit: .word,
scheme: .nameType,
options: [
.omitPunctuation,
.omitWhitespace,
.omitOther,
.joinNames
]
)
Now to actually pull out any name and place from the returned tags, we'll iterate through them and handle the ones that are for a personalName
or a placeName
:
var detectedName: String?
var detectedPlace: String?
for (tag, range) in tags {
switch tag {
case .personalName?:
detectedName = String(text[range])
case .placeName?:
detectedPlace = String(text[range])
default:
break
}
}
print("Detected name: \(detectedName)")
print("Detected place: \(detectedPlace)")
Which will print "Detected name: John Sundell" and "Detected place: Kraków". Pretty cool! 😀
Conclusion
Natural Language seems like a powerful, yet easy to use, framework for adding natural language features such as tokenization and name, language & place detection to an app. Granted, this is only a first very quick look at this new API, so I'm sure many new ways to use it (as well as bugs and quirks) will be found over the next few months.
You can test this out yourself by dropping the above code samples into a Playground in the Xcode 10 Beta and play around with it.
I hope you enjoyed this first Daily WWDC Update. Like always - your questions, comments and feedback is more than welcome - so let me know what you think of this new format on Twitter @johnsundell.
Thanks for reading! 🚀