I think the issue here is mostly that regexes are bad. I’ve started using parser combinators (often in the scala shell) for simple text manipulation like this and honestly it’s very easy: the expression reflects what it is (I forget the exact syntax but it’s something like e.g. "(" ~> string to match a string in brackets and parse it as a case class that expresses that) and case classes make it very easy to define a data model.
"(" ~> string
Procedures are very un-failsafe. What are the important benefits they’re giving us here? We need the ability to try something out and see how it matches - and I’ve seen some good efforts in this direction with e.g. interactive regex builders. But other than that, honestly I’d still rather have the value-oriented model.
It’s a disservice to cast this example in a “declarative vs. procedural” light. The language in this example provides declarative and imperative constructs. The library provides regexes. The UI provides programming-by-example (“keyboard macros”) which can incorporate the use of regexes as desired.