Конкатенатные проложенные струны

У меня есть три строки, например "A", "B", "C". Я должен создать строку, которая возникает из ее конкатенации, только вторая строка должна быть заполнена пробелом до заданной длины.

Это была моя первая попытка, основанная на интуиции и общем Scala newbiness:

val s1 = "A"
val s2 = "B"
val s3 = "C"
val padLength = 20

val s = s1 + s2.padTo(padLength, " ") + s3

что неверно, потому что padTo возвращает SeqLike, чья toString не возвращает строку внутри, а представляет собой векторное представление.

Какой был бы лучший идиоматический способ сделать это в Scala?

Ответ 1

String может быть (через неявное преобразование в StringOps здесь) рассматривается как совокупность символов, поэтому ваше дополнение должно быть

val s = s1 + s2.padTo(padLength, ' ') + s3 // note the single quotes: a char

Вызов .padTo(padLength, " ") на String на самом деле возвращает Seq[Any], поскольку в итоге вы получаете как символы, так и строки.

Ответ 2

Вы не сказали, хотите ли вы поместить влево или вправо. Просто используйте формат:

val s = f"$s1%s$s2%20s$s3"

Или, перед Scala 2.10 (или если вам нужно "20" в качестве параметра):

val s = "%s%"+padLength+"s%s" format (s1, s2, s3)

Используйте отрицательное отступы для добавления пробела вправо, а не влево.

Ответ 3

Кто-то должен упомянуть, что вы должны вызывать предупреждения:

[email protected]:~$ skala -Ywarn-infer-any
Welcome to Scala version 2.11.0-20130524-174214-08a368770c (OpenJDK 64-Bit Server VM, Java 1.7.0_21).
Type in expressions to have them evaluated.
Type :help for more information.

scala> "abc".padTo(10, "*").mkString
<console>:7: warning: a type was inferred to be `Any`; this may indicate a programming error.
       val res0 =
           ^
res0: String = abc*******

Обратите внимание, что нет ничего плохого (как такового), делая это таким образом.

Может быть, есть прецедент для:

scala> case class Ikon(c: Char) { override def toString = c.toString }
defined class Ikon

scala> List(Ikon('#'),Ikon('@'),Ikon('!')).padTo(10, "*").mkString
res1: String = #@!*******

или лучше

scala> case class Result(i: Int) { override def toString = f"$i%03d" }
defined class Result

scala> List(Result(23),Result(666)).padTo(10, "---").mkString
res4: String = 023666------------------------

Так как это не ваш случай использования, возможно, вам следует спросить, хотите ли вы использовать API, который является подробным и чреватым опасностью.

Вот почему ответ Даниила правильный. Я не уверен, почему строка формата в его примере выглядит настолько страшной, но обычно выглядит более мягкой, поскольку в большинстве читаемых строк вам нужно всего лишь форматировать символы в нескольких местах.

scala> val a,b,c = "xyz"

scala> f"$a is followed by `$b%10s` and $c%.1s remaining"
res6: String = xyz is followed by `       xyz` and x remaining

В одном случае, когда вы должны добавить ложный форматировщик, вам нужна новая строка:

scala> f"$a%s%n$b$c"
res8: String = 
xyz
xyzxyz

Я думаю, что интерполятор должен обрабатывать f "$ a% n $b". О, держись, это зафиксировано в 2.11.

scala> f"$a%n$b"  // old
<console>:10: error: illegal conversion character
              f"$a%n$b"

scala> f"$a%n$b"  // new
res9: String = 
xyz
xyz

Так что теперь нет оправдания, чтобы не интерполировать.

Ответ 4

Это работает:

val s = s1 + s2.padTo(padLength, " ").mkString + s3

но чувствует себя как-то воинственным.

Ответ 5

Доступен метод formatted. Например:

val s = s1 + s2.formatted("%-10s") + s3

а также format:

val s = s1 + "%-10s".format(s2) + s3

но я бы использовал его, только если padLength можно вставить напрямую.

Если он определен в другом месте (как в вашем примере), вы можете использовать padTo, точно так же, как указал gourlaysama.

Если вы хотите "pad left", вы можете использовать неявный класс:

object Container {
  implicit class RichChar(c: Char) {
    def repeat(n: Int): String = "".padTo(n, c)
  }

  implicit class RichString(s: String) {
    def padRight(n: Int): String = {
      s + ' '.repeat(n - s.length)
    }

    def padLeft(n: Int): String = {
      ' '.repeat(n - s.length) + s
    }
  }
}

object StringFormat1Example extends App {
  val s = "Hello"

  import Container._

  println(s.padLeft(10))
  println(s.padRight(10))
}

Ответ 6

s1 + s2 + " "*(padLength - s2.size) + s3

Ответ 7

Это стоит добавить к разным переформатам:

scala> val a = "A"; val b="B";val c="C"
a: String = A
b: String = B
c: String = C

scala> b.padTo(10, " ").mkString(a, "", c)
res1: String = AB         C

который сохраняет воскресенье + для церкви в воскресенье.

Я стал сторонником использования mkString в это действительно неуловимое коммитирование.