Kotlin 条件格式字符串

Kotlin conditional formatting string

我有三个变量:

val months: Long
val days: Long
val hours: Long

我想 return 这样的事情 :

3个月2天5小时

现在这将简单地转换为:

val str = "$months months, $days days and $hours hours"

如果我的 个月 必须是 0 作为 1 and hours as 0 那么它会像'0个月1天0小时'

但我要找的是“1 天”。我怎样才能完成它?

我绝对可以使用某种有条件的 StringBuilder 来完成这项工作,但是还有更好的 优雅 吗?

你觉得这怎么样?

fun formatTime(months: Long, days: Long, hours: Long): String =
  listOf(
    months to "months",
    days to "days",
    hours to "hours"
  )
  .filter { (length,_) -> length > 0L }
  // You can add an optional map predicate to make singular and plurals
  .map { (amount, label) -> amount to if(abs(amount)==1L) label.replace("s", "") else label }
  .joinToString(separator=", ") { (length, label) -> "$length $label" }
  .addressLastItem()

fun String.addressLastItem() =
  if(this.count { it == ','} >= 1) 
    // Dirty hack to get it working quickly
    this.reversed().replaceFirst(" ,", " dna ").reversed() 
  else 
    this

您可以看到它正在运行 over here

另一种不替换、计数或反转列表的变体:

fun formatTime(months: Long, days: Long, hours: Long): String {
  val list = listOfNotNull(
    months.formatOrNull("month", "months"),
    days.formatOrNull("day", "days"),
    hours.formatOrNull("hour", "hours"),
  )
  return if (list.isEmpty()) "all values <= 0"
  else
    listOfNotNull(
      list.take(list.lastIndex).joinToString().takeIf(String::isNotEmpty),
      list.lastOrNull()
    ).joinToString(" and ")
}

fun Long.formatOrNull(singular: String, plural: String = "${singular}s") = when {
  this == 1L -> "$this $singular"
  this > 1L -> "$this $plural"
  else -> null
}

如果所有值都 <= 0,它也有回退...您也可以只使用空字符串或您喜欢的任何内容。

如果您不喜欢创建中间列表来连接字符串,您也可以在 else 路径中使用如下内容:

list.iterator().run {
  buildString {
    while (hasNext()) {
      val part = next()
      if (length > 0)
        if (hasNext())
          append(", ")
        else
          append(" and ")
      append(part)
    }
  }
}