I have the following function that uses Swift 5.7
's Regex
builder:
static func numberStartingWith6(strictLength: Bool) -> some RegexComponent {
let myRegex = Regex {
Optionally {
"6"
if strictLength {
Repeat(CharacterClass.digit, count: 9)
}
else {
Repeat(0...8) {
CharacterClass.digit
}
}
}
}
but i get the following syntax error at the Optionally
type:
Type '() -> ()' cannot conform to 'RegexComponent'
I tried to figure out the underlying type of the myRegex
variable in the function above and it was:
Regex<Regex<Optionally<Substring>. RegexOutput>. RegexOutput>
How to declare the correct return type in the function's signature so that I don't care about the regex builder's underlying type (i.e. type erasure).
RegexComponentBuilder
doesn't support if
statements. There is no buildEither
or buildIf
methods.
The error is rather confusing. Since you used an if
statement in the closure, the compiler no longer thinks this is a @RegexComponentBuilder
closure, and tries to match the other initialiser overloads. It found this overload that takes a RegexComponent
, and says the closure (of type () -> ()
) can't be converted to that.
if
statements are not supported possibly because if the branches capture different things, the Output
type of the resulting regex is going to be very complicated.
For example, if you have
if x {
// here you capture an Int, a Substring, and a Double
} else if y {
// here you capture an Double, a Float, and a Date
} else {
// here you capture a Decimal, a Boolean and a Substring
Then the Output
type of the regex would be
(Substring, Int?, Substring?, Double?, Double?, Float?, Date?, Decimal?, Boolean?, Substring?)
or
(Substring, (Int, Substring, Double)?, (Double, Float, Date)?, (Decimal, Boolean, Substring)?)
The amount of buildEither
and buildIf
overloads needed for this is rather unmanageable.
You can write a buildEither
yourself if you only capture the same types in each branch:
// this won't work if you capture different types in each branch of an if
extension RegexComponentBuilder {
static func buildEither<T>(first component: Regex<T>) -> Regex<T> {
buildPartialBlock(first: component)
}
public static func buildEither<T>(second component: Regex<T>) -> Regex<T> {
buildPartialBlock(first: component)
}
}
That said, your code does not need an if statement. Just do:
Repeat(strictLength ? 9...9 : 0...8) {
CharacterClass.digit
}
Or if the regex component in each branch is a different type, you can just declare a let
:
Regex {
Optionally {
"6"
let temp: any RegexComponent<Substring /* or any other output you want*/> = {
if strictLength {
return ChoiceOf {
"a"
CharacterClass.digit
}
} else {
return Optionally {
"b"
}
}
}()
// then use temp somewhere...
temp
}
}