Конкатенатные проложенные струны
У меня есть три строки, например "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 в это действительно неуловимое коммитирование.