2013-06-07 3 views
11

У меня есть три строки, например «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?

+0

+1 для интуиции + новобрачность. –

ответ

19

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

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

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

2

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

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

но чувствует себя как-то ненадежный.

+0

Лучшая формулировка: b.padTo (10, "") .mkString (a, "", c) –

+0

@ som-snytt yes yes yes, slapface time. –

8

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

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

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

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

использовать отрицательные отступы, чтобы добавить отступ пространство справа, а не слева ,

+1

Для тех, кто не поднял планку, подключился к опасностям настройки тупой небольшой подпрограммы, http://scalapuzzlers.com/#pzzlr-027, а также при добавлении https://github.com/scala/scala /blob/master/src/compiler/scala/tools/nsc/Global.scala#L751. –

2

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

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

, а также format:

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

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

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

Если вы хотите «подушечка влево», вы могли бы использовать неявный класс:

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)) 
} 
5

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

[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 

Я думаю, интерпол должен обрабатывать п «$ а% п $ Ь». О, держись, это зафиксировано в 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 

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

+0

+1 для объяснений. Что мне не нравится в ответе Даниэля, так это то, что интерполированная строка намного менее читаема, чем опция .padTo. –

1

Это стоит добавить к MISC переформулировок:

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 

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

Я стал сторонником эксплуатации mkString по адресу this really wonky commit.

Смежные вопросы