Apply several string transformations in scala
If its just a few invocations then just chain them. Otherwise I guess I'd try this:
Seq("a" -> "b", "b" -> "a").foldLeft("abab"){case (z, (s,r)) => z.replaceAll(s, r)}
Or if you like shorter code with confusing wildcards and extra closures:
Seq("a" -> "b", "b" -> "a").foldLeft("abab"){_.replaceAll _ tupled(_)}
First, let's get a function out of the replaceAll
method:
scala> val replace = (from: String, to: String) => (_:String).replaceAll(from, to)
replace: (String, String) => String => java.lang.String = <function2>
Now you can use Functor
instance for function, defined in scalaz. That way you can compose functions, using map
(or to make it look better, using unicode aliases).
It will look like this:
scala> replace("from", "to") ∘ replace("to", "from") ∘ replace("some", "none")
res0: String => java.lang.String = <function1>
If you prefer haskell-way compose (right to left), use contramap
:
scala> replace("some", "none") ∙ replace("to", "from") ∙ replace ("from", "to")
res2: String => java.lang.String = <function1>
You can also have some fun with Category
instance:
scala> replace("from", "to") ⋙ replace("to", "from") ⋙ replace("some", "none")
res5: String => java.lang.String = <function1>
scala> replace("some", "none") ⋘ replace("to", "from") ⋘ replace ("from", "to")
res7: String => java.lang.String = <function1>
And applying it:
scala> "somestringfromto" |> res0
res3: java.lang.String = nonestringfromfrom
scala> res2("somestringfromto")
res4: java.lang.String = nonestringfromfrom
scala> "somestringfromto" |> res5
res6: java.lang.String = nonestringfromfrom
scala> res7("somestringfromto")
res8: java.lang.String = nonestringfromfrom
Another Scalaz-based solution to this problem would be to use the Endo
monoid. This monoid captures the identity function (as the monoid's identity element) and function composition (as the monoid's append operation). This solution would be particularly useful if you have an arbitrarily-sized (even possibly empty) list of functions to apply.
val replace = (from: String, to: String) => (_:String).replaceAll(from, to)
val f: Endo[String] = List(
replace("some", "none"),
replace("to", "from"),
replace("from", "to")
).foldMap(_.endo)
e.g. (using one of folone's examples)
scala> f.run("somestringfromto")
res0: String = nonestringfromfrom