I'm working on a RESTful app in Kotlin and for the router, I'm using a when statement, as it's the most readable and good looking conditional.
Is there a way to use Regex or a wildcard in the when statement for a string?
(So that URIs like "/article/get/" would all be passed to the same controller)
The structure of my router is as follows:
when(uri) {
"some/url" -> return SomeController(config).someAction(session)
}
Wildcards are different from the regular expressions used in grep (although they may look similar at times). Wildcards apply to all commands including grep and are used in place of or in combination with operands. Regular Expressions only apply to grep and a few other UNIX commands.
In regular expressions, the period ( . , also called "dot") is the wildcard pattern which matches any single character. Combined with the asterisk operator . * it will match any number of any characters.
Wildcard Pattern Matching: Given a string and a pattern containing wildcard characters, i.e., * and ? , where ? can match to any single character in the string and * can match to any number of characters including zero characters, design an efficient algorithm to check if the pattern matches with the complete string or ...
You can repeat expressions with an asterisk or plus sign. A regular expression followed by an asterisk ( * ) matches zero or more occurrences of the regular expression. If there is any choice, the first matching string in a line is used.
Yes.
import kotlin.text.regex
val regex1 = Regex( /* pattern */ )
val regex2 = Regex( /* pattern */ )
/* etc */
when {
regex1.matches(uri) -> /* do stuff */
regex2.matches(uri) -> /* do stuff */
/* etc */
}
You could also use containsMatchIn
if that suits your needs better than matches
.
Explanation:
The test expression of a when
statement is optional. If no test expression is included, then the when
statement functions like an if-else if
chain, where the whenCondition
of each whenEntry
shall independently evaluate to a boolean.
EDIT:
So I thought about it for awhile, and I came up with a different approach that might be closer to what you want.
import kotlin.text.regex
when (RegexWhenArgument(uri)) {
Regex(/* pattern */) -> /* do stuff */
Regex(/* pattern */) -> /* do stuff */
/* etc */
}
Where RegexWhenArgument
is minimally defined as:
class RegexWhenArgument (val whenArgument: CharSequence) {
operator fun equals(whenEntry: Regex) = whenEntry.matches(whenArgument)
override operator fun equals(whenEntry: Any?) = (whenArgument == whenEntry)
}
This approach lets you get as close as possible to the "argument-ful" when
expression syntax. I think it's about as streamlined and readable as it can be (assuming that you define the RegexWhenArgument
class elsewhere).
This approach uses something similar to the visitor design pattern in combination with Kotlin's operator overloading to redefine what constitutes a "match" between a when
expression argument and a whenEntry
. If you really wanted to, I suppose you could take this approach a step further and generify RegexWhenArgument
into a general-purpose WhenArgument
and WhenArgumentDecorator
that allows you to specify custom "match" criteria in a when
expression for any sort of type, not just Regex.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With