Can the switch case statement with a Swift regex literal expression be somehow modified to function OK?
Yes, a case let … where …
pattern with a /regex/
literal can be used. This approach can also be implemented in a way that expressly avoids potential ~=
future ambiguities relative to the standard library. This approach is an alternative to directly defining ~=
.
Note that defining your own ~= will not create errors down the road, because overload resolution favors operations defined outside the standard library over those defined in the standard library. It could result in confusion for developers reading your source, however. - Stephen Canon comment -
Discussion…
Match-Part-Or-Whole Example - A fundamental approach where the original regex pattern /^…$/
is used to match a entire line:
extension String {
func matchFirst(_ regex: Regex<Substring>) -> Bool {
// errors count as "not match"
(try? regex.firstMatch(in: self)) != nil
}
}
switch "---abc---" {
case let s where s.matchFirst(/^\w+$/):
print("entire line contains alphanumerics: '\(s)'")
case let s where s.matchFirst(/\w+/):
print("alphanumerics found in string: '\(s)'")
default:
print("no alphanumerics found")
}
Whole-Match-Only Example - A "whole match only" regex approach where a partial match is not possible:
extension String {
func matchWhole(_ regex: Regex<Substring>) -> Bool {
// errors count as "not match"
(try? regex.wholeMatch(in: self)) != nil
}
}
switch "---abc---" {
case let s where s.matchWhole(/\w+/):
print("all alphanumerics: '\(s)'")
//case partial match not available. whole or nothing.
default:
print("no match for /\\w+/")
}
I ended up using the "classic" Match-Part-Or-Whole Example approach instead of the Whole-Match-Only Example and func ~=
approaches for the following reasons:
func ~=
- could possibly be defined by Swift at some future time. Possible future confusion.
- Whole-Match-Only Example - does not support both partial and full matches. Less expressive.
- Match-Part-Or-Whole Example
- leaves
~=
undefined which allows for the possible future definition by Swift. Avoids possible future confusion.
- does support both partial and full matches. More expressive.
^…$
is expressly stated for a full line match. More readable.
Note: Extending String
with both convenience wrappers, such as matchFirst
and matchWhole
, can allow for either approach to be choosen at the point of use. This approach provides the following benefits:
- expressive
- co-locates both choices in the point-of-use autocompletion list
- avoids the conflict of one vs the other in the lower level extension
- does not presume any interpretation for the not-yet-officially-defined
~=
.
extension String {
func matchFirst(_ regex: Regex<Substring>) -> Bool {
// errors count as "not match"
(try? regex.firstMatch(in: self)) != nil
}
func matchWhole(_ regex: Regex<Substring>) -> Bool {
// errors count as "not match"
(try? regex.wholeMatch(in: self)) != nil
}
}
Historic Footnote
The ^
begin-anchor and $
end-anchor syntax has been part of Regular Expressions since the 1970s with qed
and ed
PDP-7 AT&T Bell Labs Unix editors.
QED Text Editor (1970 Bell Telephone Laboratories technical memorandum)
ed (see man ed
or info ed
on POSIX and Open Group compliant Unix-like systems)
See also man ed
and info ed
on modern BSD/Linux/Unix systems. It's still there.
The ^
begin-anchor and $
end-anchor syntax was also carried forward to other Regular Expression enabled software tools, such as sed
, g/re/p
global regular expression, Perl Compatible Regular Expressions (PCRE) library, and POSIX standard Basic Regular Syntax (BRE).
If /^.$/
pattern is implied and hidden for some compact code convenience then the REGEX expressive capability is reduced.
Seeing, reading, and writing with ^
begin-anchor and $
end-anchor syntax can be natural (and even expected) for an experienced REGEX user.
/^…$/
to match the full string" coding habit. So,firstMatch
works very well with the patterns I have. Easy choice. Thanks. – Highstepper