Swift Regex introduced in Swift 5.7
Hi there, I’d like to show you how to use Swift Regex, which was introduced in Swift 5.7🎉
How we use the regex before introducing Swift Regex?
When not to use Swift Regex, we use the things below.
- NSRegularExpression
- The methods come from NSString
・range(of:options:range:locale:)
・replacingOccurrences(of:with:options:range:)
・etc…
Here are the reasons that I think NSRegularExpression is such a fiddly thing to use :(
- We have to use “try” just to instantiate NSRegularExpression class, so this makes us think about the situation some errors occur.
- To write a regex, we have to write double escape.
- To get the final achievement, we have to use NSRange and Range.
- Optional binding(I’ve omitted in the example above) is needed to get the result.
But fortunately, we don’t have to be bothered if we use Swift Regex 🎉
What is the advantages of Swift Regex compared to the old one?
1. Literals are concise; builders give structure.
It looks apparently more intuitive when we use Swift Regex and Regex builders(thanks to resultBuilder which is described later).
2. Interweave real parsers as parts of regex
We can use the parsers which has originally existed parsers. (i.e., Date.ParseStrategy)
And more, we can use custom parser if we prepare the type conforming CustomConsumingRegexComponent.
3. Regex does Unicode
These two features have been implemented.
i: Canonical Equivalents
ii: Extended Grapheme Clusters and Character Classes with Strings
4. Predictable execution, prominent controls
If we use Swift Regex, we can get advantage of the reasoning, and reduce mistakes at compile-time!
How to use a Swift Regex?
There are 3 ways to use it.
1. Regex literals
We can write really concisely. Actually, we don't have to write double escape and consider do-catch anymore unlike NSRegularExpression! Awesome!!
2. Run-time construction
This is useful for search fields in editors or command-line tools.
This will throw an error at run-time if the input of Regex.init(_:) is invalid. The output type will be AnyRegexOutput though. Here is the way to extract the value.
We can extract the result by using extractValues(as:), but I couldn’t get the value if I try to use String.self as input.
As a side note, the content of match.output was like this.
AnyRegexOutput(input: “2023–03–20”, _elements: [_StringProcessing.AnyRegexOutput.ElementRepresentation(optionalDepth: 0, content: Optional((range: Range(Swift.String.Index(_rawBits: 15)..<Swift.String.Index(_rawBits: 655367)), value: nil)), name: nil, referenceID: nil)])
3. Regex builders
I suppose this is the most well-structured way to write!
It is really intuitive way to read!! And of course, a bunch of fiddly things which is required for NSRegularExpression is no longer needed 🎉
And the reason why we can write Regex in such an intuitive way is resultBuilder. Here is the actual implementation.
Some types which we can use to build Regex 🎉
I’d like to show you some types which conform to RegexComponent. We can use these types for instantiating Regex.
One
This is the type to prove there is only one thing specified at input(which is date(_:locale:timeZone:calendar:) in the example below).
If there is 0 or more than 2, the content of “match” would be nil.
ZeroOrMore
This is the type to prove there aren’t different characters other than specified one. Thus, even if specified characters are not there, it’s ok.
OneOrMore
This is the type to prove there are more than one specified characters. Thus, if there is no specified characters, the content of “match” would be nil.
Repeat
This is the type to prove there are the specified number of specified characters.
Capture
If we use this, we can extract each value from a specified key!
We don’t have to specify the type of each key if we use Regex literals :)
TryCapture
If we use this, we can transform the captured value and convert it!
Tips 👩💻
Xcode features
You can convert from Regex builders to Regex literals automatically like this! Perfect! Thus, even though you are not familiar Regex builders, it’s fine!