/** * Re-creating the format function -- at least sort of. * And doing it is a pure-functional way * But I do cheat and use the format funtion. * Also gratuitously using an enum * * @author gtowell * Created: August 2021 * Modified: Nov 2021 */ enum class Formats { s, d, f } fun main() { println(sprintf2("%s%d%f", "this", 1, 2.3)) println(sprintf2("%s%d", "this", 42, "that")) } fun sprintf2(fmt:String, vararg qq:Any) : String { fun isp(fmmt:List, vargs:List):String { if (vargs.size==0) { return "" } if (fmmt.size == 0) { return ""} val q = vargs.first() when (fmmt.first()) { // this really just checks the type of each arg against the // format string, then it calls format. With more work, I could // get rid of the use if format entirely. Formats.s.name -> if (q is String) { return "%s %s".format(q, isp(fmmt.drop(1), vargs.drop(1))) } else { println("type mismatch ${fmmt.first()} $q"); return isp(fmmt.drop(1), vargs.drop(1)) } Formats.d.name -> if (q is Int) { return "%d %s".format(q, isp(fmmt.drop(1), vargs.drop(1))) } else { println("type mismatch ${fmmt.first()} $q"); return isp(fmmt.drop(1), vargs.drop(1)) } Formats.f.name -> if (q is Double) { return "%f %s".format(q, isp(fmmt.drop(1), vargs.drop(1))) } else { println("type mismatch ${fmmt.first()} $q"); return isp(fmmt.drop(1), vargs.drop(1)) } else -> { println("unknown format ${fmmt.first()}"); return isp(fmmt.drop(1), vargs.drop(1)) } } } return isp(fmt.split("%").drop(1), qq.toList()) }