Повністю обґрунтуйте і переносіть текст тексту


26
Given  a width  and  a block  of
text containing possible hyphen-
ation points,  format it  fully-
justified (in monospace).

Цілком виправдано означає, що він вирівняний зліва та праворуч і досягається збільшенням відстані між словами, поки кожен рядок не підійде.

Пов'язані:

Вхідні дані

Ви можете взяти вхід у будь-якому форматі, який вам подобається. Вам дадуть:

  • Цільова ширина (у символах), в межах 5-100 (включно);
  • Блок тексту, що містить можливо дефісні слова. Це може бути рядок, розділений пробілом, масив слів або масив масивів фрагментів слів (або будь-яке інше подання даних, яке ви хочете).

Типовим входом може бути:

Width: 25
Text:  There's no bu-si-ne-ss lik-e s-h-o-w busine-ss, n-o bus-iness I know.

Де дефіси позначають можливі точки переносу, а пробіли позначають межі слова. Можливе альтернативне подання тексту:

[["There's"], ["no"], ["bu", "si", "ne", "ss"], ["lik", "e"], (etc.)]

Вихідні дані

Текст вводу з пробілами, доданими між словами, новими рядками на ширині стовпця та пунктами переносу, вибраними для повного виправдання його до ширини стовпця. Для функцій може бути повернутий масив рядків (по одному для кожного рядка), а не використовувати розділення нового рядка.

Можливим виходом для вищевказаного входу може бути:

There's no  business like
show  business,  no  bus-
iness I know.

Зауважте, що всі дефіси було видалено, окрім тієї, що міститься у фінальній "шині", яка показує, що слово переходить у наступний рядок, і було вибрано для того, щоб другий рядок містив якомога більше тексту.

Правила

  • У кожному рядку кількість пробілів між словами не може змінюватися більш ніж на 1, але там, де ви вставляєте зайві пробіли, залежить від вас:

    hello hi foo     bar    <-- not permitted (1,1,5)
    hello  hi foo    bar    <-- not permitted (2,1,4)
    hello  hi  foo   bar    <-- OK (2,2,3)
    hello  hi   foo  bar    <-- OK (2,3,2)
    hello   hi  foo  bar    <-- OK (3,2,2)
    
  • Жоден рядок не може починатися або закінчуватися пробілами (крім останнього рядка, який може закінчуватися пробілами).

  • Останній рядок слід залишити виправданим і містити поодинокі пробіли між кожним словом. За бажанням може дотримуватися довільний пробіл / новий рядок, але це не потрібно.

  • Слова складаються з AZ, az, 0-9 та простої пунктуації ( .,'()&)

  • Ви можете припустити, що жоден фрагмент слова не буде довше цільової ширини, і рядки завжди можна буде заповнити відповідно до правил (тобто у кожному рядку буде принаймні 2 фрагменти слова, або 1 слово, який заповнює рядок ідеально)

  • Ви повинні вибрати пункти переносу, які максимізують кількість символьних слів у попередніх рядках (тобто слова повинні вживатись жадібно рядками), наприклад:

    This is an input stri-ng with hyph-en-at-ion poi-nts.
    
    This     is     an     input    stri-      <-- not permitted
    ng with hyphenation points.
    
    This  is an  input string  with hyph-      <-- not permitted
    enation points.
    
    This is an input  string with hyphen-      <-- OK
    ation points.
    
  • Виграє найкоротший код у байтах

Приклади

Width: 20
Text:  The q-uick brown fox ju-mp-s ove-r t-h-e lazy dog.

The quick  brown fox
jumps over the  lazy
dog.

Width: 32
Text: Given a width and a block of text cont-ain-ing pos-sible hyphen-ation points, for-mat it ful-ly-just-ified (in mono-space).

Given  a width  and  a block  of
text containing possible hyphen-
ation points,  format it  fully-
justified (in monospace).

Width: 80
Text:  Pro-gram-ming Puz-zles & Code Golf is a ques-tion and ans-wer site for pro-gram-ming puz-zle enth-usi-asts and code golf-ers. It's built and run by you as part of the St-ack Exch-ange net-work of Q&A sites. With your help, we're work-ing to-g-et-her to build a lib-rary of pro-gram-ming puz-zles and their sol-ut-ions.

Programming Puzzles &  Code Golf  is a question and answer  site for programming
puzzle enthusiasts  and code golfers.  It's built and run  by you as part of the
Stack Exchange network  of Q&A sites. With your help,  we're working together to
build a library of programming puzzles and their solutions.

Width: 20
Text:  Pro-gram-ming Puz-zles & Code Golf is a ques-tion and ans-wer site for pro-gram-ming puz-zle enth-usi-asts and code golf-ers. It's built and run by you as part of the St-ack Exch-ange net-work of Q&A sites. With your help, we're work-ing to-g-et-her to build a lib-rary of pro-gram-ming puz-zles and their sol-ut-ions.

Programming  Puzzles
&  Code  Golf  is  a
question and  answer
site for programming
puzzle   enthusiasts
and  code   golfers.
It's  built  and run
by  you  as  part of
the  Stack  Exchange
network    of    Q&A
sites.   With   your
help,  we're working
together to  build a
library of  program-
ming   puzzles   and
their solutions.

Width: 5
Text:  a b c d e f g h i j k l mm nn oo p-p qq rr ss t u vv ww x yy z

a b c
d e f
g h i
j k l
mm nn
oo pp
qq rr
ss  t
u  vv
ww  x
yy z

Width: 10
Text:  It's the bl-ack be-ast of Araghhhhh-hhh-h-hhh-h-h-h-hh!

It's   the
black  be-
ast     of
Araghhhhh-
hhhhhhhhh-
hhh!

Так, нарешті черговий (текстовий) типографічний виклик :-)
ETHproductions

1
@ Adám так для вбудованих: немає обмежень на код, і найкоротший виграш коду. Хоча, звичайно, це може дати нудну відповідь! Щодо бібліотек, ви можете до тих пір, поки бібліотека буде у вільному доступі, і ви позначите свою відповідь як "мова + бібліотека". Також бібліотечна версія повинна попередньо поставити перед цим завданням.
Дейв

1
У тому випадку, якщо рядок може закінчуватися дефісом або одним символом, наприклад, anybod-yшириною 7, ми можемо вибрати вихід anybodyабо anybod-\ny?
darrylyeo

1
@JonathanAllan так; вибачте, я це виправлю
Дейв

3
@darrylyeo ні, вам не доведеться виводити повне слово в цьому випадку, оскільки воно повинно жадібно мати якомога більше символів слова в кожному рядку.
Дейв

Відповіді:


7

JavaScript (ES6), 218 байт

w=>s=>s.map((c,i)=>c.map((p,j)=>(k+p)[l="length"]-w-(b=!i|j>0)+(j<c[l]-1)<0?k+=b?p:" "+p:(Array(w-k[l]-b).fill(h=k.split` `).map((_,i)=>h[i%(h[l]-1)]+=" "),o.push(h.join` `+(b?"-":"")),k=p)),o=[],k="")&&o.join`
`+`
`+k

Бере аргументи в синтаксисі currying ( f(width)(text)), а введення тексту - у форматі подвійного масиву, описаному в виклику. Рядки конвертуються у цей формат через.split` `.map(a=>a.split`-`)) . Також рядки є буквально новими рядками всередині рядків шаблону.

Без гольфу та перестановки

width=>string=> {
    out=[];
    line="";
    string.map((word,i)=> {
        word.map((part,j)=> {

            noSpaceBefore = i==0 || j>0;
            if ((line+part).length - width - noSpaceBefore + (j<word.length-1) < 0) {
                line += noSpaceBefore ? part : " "+part;
            }
            else {
                words=line.split` `;
                Array(width - line.length - noSpaceBefore).fill()
                    .map((_,i) => words[i % (words.length-1)] += " ");
                out.push(words.join(" ") + (noSpaceBefore? "-" : ""));
                line=part;
            }
        });
    });
    return out.join("\n") + "\n"+line
}

Ідея тут полягала в тому, щоб переходити через кожну частину всього рядка і створювати кожен рядок по одній. Як тільки рядок був заповнений, він збільшує проміжок слів зліва направо, поки не будуть розміщені всі зайві пробіли.

Тест-фрагмент

f=
w=>s=>s.map((c,i)=>c.map((p,j)=>(k+p)[l="length"]-w-(b=!i|j>0)+(j<c[l]-1)<0?k+=b?p:" "+p:(Array(w-k[l]-b).fill(h=k.split` `).map((_,i)=>h[i%(h[l]-1)]+=" "),o.push(h.join` `+(b?"-":"")),k=p)),o=[],k="")&&o.join`
`+`
`+k
<style>*{font-family:Consolas,monospace;}</style>
<div oninput="O.innerHTML=f(+W.value)(S.value.split` `.map(a=>a.split`-`))">
Width: <input type="number" size="3" min="5" max="100" id="W">
Tests: <select id="T" style="width:20em" oninput="let x=T.value.indexOf(','),s=T.value;W.value=s.slice(0,x);S.value=s.slice(x+2)"><option></option><option>20, The q-uick brown fox ju-mp-s ove-r t-h-e lazy dog.</option><option>32, Given a width and a block of text cont-ain-ing pos-sible hyphen-ation points, for-mat it ful-ly-just-ified (in mono-space).</option><option>80, Pro-gram-ming Puz-zles & Code Golf is a ques-tion and ans-wer site for pro-gram-ming puz-zle enth-usi-asts and code golf-ers. It's built and run by you as part of the St-ack Exch-ange net-work of Q&A sites. With your help, we're work-ing to-g-et-her to build a lib-rary of pro-gram-ming puz-zles and their sol-ut-ions.</option><option>20, Pro-gram-ming Puz-zles & Code Golf is a ques-tion and ans-wer site for pro-gram-ming puz-zle enth-usi-asts and code golf-ers. It's built and run by you as part of the St-ack Exch-ange net-work of Q&A sites. With your help, we're work-ing to-g-et-her to build a lib-rary of pro-gram-ming puz-zles and their sol-ut-ions.</option><option>5, a b c d e f g h i j k l mm nn oo p-p qq rr ss t u vv ww x yy z</option><option>10, It's the bl-ack be-ast of Araghhhhh-hhh-h-hhh-h-h-h-hh</option></select><br>
Text: &nbsp;<textarea id="S" cols="55" rows="4"></textarea>
</div>
<pre id="O" style="border: 1px solid black;display:inline-block;"></pre>


8

GNU sed -r, 621 байт

Вводить введення у вигляді двох рядків: Ширина - уніарне число першої та рядок - друге.

Я впевнений, що це може бути набагато більше гольфу, але я вже скидав занадто багато часу на це.

x;N
G
s/\n/!@/
:
/@\n/bZ
s/-!(.*)@ /\1 !@/
s/!(.*[- ])(@.*1)$/\1!\2/
s/@(.)(.*)1$/\1@\2/
s/-!(.*-)(@.*)\n$/\1!\2\n1/
s/(\n!@) /\1/
s/-!(.* )(@.*)\n$/\1!\2\n1/
s/-!(.*-)(@.*1)$/\1!\21/
s/!(.*)-@([^ ]) /\1\2!@ /
t
s/ !@(.*)\n$/\n!@\1#/
s/!(.*-)@(.*)\n$/\1\n!@\2#/
s/!(.*)(@ | @)(.*)\n$/\1\n!@\3#/
s/-!(.*[^-])@([^ ]) (.*)\n$/\1\2\n!@\3#/
s/!(.+)@([^ ].*)\n$/\n!@\1\2#/
/#|!@.*\n$/{s/#|\n$//;G;b}
:Z
s/-?!|@.*//g
s/ \n/\n/g
s/^/%/
:B
G
/%.*\n.+\n/!bQ
:C
s/%([^\n])(.*)1$/\1%\2/
tC
s/([^\n]+)%\n/%\1\n/
:D
s/%([^ \n]* )(.*)1$/\1 %\2/
tD
s/(^|\n)([^\n]+)%(.*1)$/\1%\2\3/
tD
s/%([^\n]*)\n(.*)\n$/\1\n%\2/
tB
:Q
s/%(.*)\n1*$/\1/

Спробуйте в Інтернеті!

Пояснення

Програма працює у два етапи: 1. Розбийте та 2. Обґрунтуйте. Нижче, припустимо, наш внесок:

111111111111
I re-mem-ber a time of cha-os, ru-ined dreams, this was-ted land.

Налаштування

Спочатку ми читаємо введення, переміщуючи перший рядок (ширина як одинарне число) до місця утримування ( x), потім додаючи наступний рядок ( N), а потім копію ширини з місця утримування ( G) до простору шаблону. Оскільки Nнам залишився ведучий, \nми замінимо його !@, яким ми скористаємось як курсори в 1-й фазі.

x;N
G
s/\n/!@/

Тепер вміст простору утримування є 1111111111111(і не змінюватиметься відтепер), а простір шаблону є (у форматі команди "однозначно друкувати" l):

!@I re-mem-ber a time of cha-os, ru-ined dreams, this was-ted land.\n111111111111$

Фаза 1

У Фазі 1 основний @курсор просуває по одному символу за часом, а для кожного символу a 1видаляється з "лічильника" в кінці простору візерунка. Іншими словами, @foo\n111$, f@oo\n11$, fo@o\n1$і т.д.

У !курсор Траси позаду @курсора, відзначаючи місця , де ми могли б зламатися , якщо лічильник досягає 0 в середині рядка. Кілька раундів виглядатиме так:

!@I re-mem-ber a time of cha-os, ru-ined dreams, this was-ted land.\n111111111111$
!I@ re-mem-ber a time of cha-os, ru-ined dreams, this was-ted land.\n11111111111$
!I @re-mem-ber a time of cha-os, ru-ined dreams, this was-ted land.\n1111111111$

Тут ми розпізнаємо шаблон: пробіл одразу слідом за @курсором. Оскільки лічильник більший за 0, ми просуваємо маркер розриву, а потім продовжуємо просувати головний курсор:

I !@re-mem-ber a time of cha-os, ru-ined dreams, this was-ted land.\n1111111111$
I !r@e-mem-ber a time of cha-os, ru-ined dreams, this was-ted land.\n111111111$
I !re@-mem-ber a time of cha-os, ru-ined dreams, this was-ted land.\n11111111$
I !re-@mem-ber a time of cha-os, ru-ined dreams, this was-ted land.\n1111111$

Ось ще одна закономірність: -@і у нас ще є 7 у лічильнику, тому ми пересуваємо курсор перерви ще раз і продовжуємо просуватися:

I re-!mem-@ber a time of cha-os, ru-ined dreams, this was-ted land.\n111$

Ось інша картина: Дефіс безпосередньо перед курсором розриву та інший, що передує головному курсору. Видаляємо перший дефіс, просуваємо курсор перерви і, оскільки ми видалили символ, додаємо 1 до лічильника.

I remem-!@ber a time of cha-os, ru-ined dreams, this was-ted land.\n1111$

Ми продовжуємо просувати головний курсор:

I remem-!ber@ a time of cha-os, ru-ined dreams, this was-ted land.\n1$

Як і раніше, але цього разу головний курсор передує пробілу, а не слідує дефісом. Ми видаляємо дефіс, але оскільки ми також просуваємо головний курсор, ми не збільшуємо жодного зменшення лічильника.

I remember !@a time of cha-os, ru-ined dreams, this was-ted land.\n1$
I remember !a@ time of cha-os, ru-ined dreams, this was-ted land.\n$

Нарешті, наш лічильник досяг нуля. Оскільки символ після основного курсору є пробілом, ми вставляємо новий рядок і ставимо обидва курсора відразу після нього. Потім поповнюємо лічильник ( G) і починаємо заново.

I remember a\n!@ time of cha-os, ru-ined dreams, this was-ted land.\n111111111111$

Фаза 1 триває, просуваючи курсори та узгоджуючи різні візерунки, поки @курсор не досягне кінця рядка.

# Phase 1
:
  # End of string; branch to :Z (end of phase 1)
  /@\n/bZ

  # Match -!.*@_
  s/-!(.*)@ /\1 !@/

  # Match [-_]@ and >0
  s/!(.*[- ])(@.*1)$/\1!\2/

  # Advance cursor
  s/@(.)(.*)1$/\1@\2/

  # Match -!.*-@ and 0; add 1
  s/-!(.*-)(@.*)\n$/\1!\2\n1/

  # Match \n!@_
  s/(\n!@) /\1/

  # Match -!.*_@ and 0; add 1
  s/-!(.* )(@.*)\n$/\1!\2\n1/

  # Match -!.*-@ and >0; add 1
  s/-!(.*-)(@.*1)$/\1!\21/

  # Match -@[^_]_
  s/!(.*)-@([^ ]) /\1\2!@ /

  # If there were any matches, branch to `:`
  t

  # Match _!@ and 0
  s/ !@(.*)\n$/\n!@\1#/

  # Match -@ and 0
  s/!(.*-)@(.*)\n$/\1\n!@\2#/

  # Match @_|_@ and 0
  s/!(.*)(@ | @)(.*)\n$/\1\n!@\3#/

  # Match -!.*[^-]@[^_]_ and 0
  s/-!(.*[^-])@([^ ]) (.*)\n$/\1\2\n!@\3#/

  # Match !.+@[^_] and 0
  s/!(.+)@([^ ].*)\n$/\n!@\1\2#/

  # Match marked line (#) or !@ and 0
  /#|!@.*\n$/{
    # Remove mark; append width and branch to `:`
    s/#|\n$//
    G
    b
  }

:Z

# Cleanup
s/-?!|@.*//g
s/ \n/\n/g

Наприкінці 1 фази наш простір візерунка виглядає приблизно так:

I remember a\ntime of cha-\nos, ruined\ndreams, this\nwasted land.

Або:

I remember a
time of cha-
os, ruined
dreams, this
wasted land.

2 фаза

У Фазі 2 ми використовуємо %як курсор і використовуємо лічильник аналогічно, починаючи так:

%I remember a\ntime of cha-\nos, ruined\ndreams, this\nwasted land.\n111111111111$

Спочатку ми підраховуємо символи в першому рядку, просуваючи курсор і видаляючи 1s з лічильника, після чого маємо;

I remember a%\ntime of cha-\nos, ruined\ndreams, this\nwasted land.\n$

Оскільки лічильник 0, ми нічого більше не робимо в цій лінії. Другий рядок також має таку ж кількість символів, що і лічильник, тому перейдемо до третього рядка:

I remember a\ntime of cha-\nos, ruined%\ndreams, this\nwasted land.\n11$

Лічильник більший за 0, тому ми переміщуємо курсор назад на початок рядка. Потім ми знаходимо перший пробіл пробілів і додаємо пробіл, декрементуючи лічильник.

I remember a\ntime of cha-\nos, % ruined\ndreams, this\nwasted land.\n1$

Лічильник більший за 0; оскільки курсор вже в останньому (єдиному) пробілі пробілів на лінії, ми переміщаємо його назад на початок рядка і робимо це знову:

I remember a\ntime of cha-\nos,  % ruined\ndreams, this\nwasted land.\n$

Тепер лічильник дорівнює 0, тому переміщуємо курсор на початок наступного рядка. Повторюємо це для кожного рядка, крім останнього. Ось кінець другої фази та кінець програми! Кінцевий результат:

I remember a
time of cha-
os,   ruined
dreams, this
wasted land.
# Phase 2
# Insert cursor
s/^/%/
:B
  # Append counter from hold space
  G
  # This is the last line; branch to :Q (end of phase 1)
  /%.*\n.+\n/!bQ

  :C
    # Count characters
    s/%([^\n])(.*)1$/\1%\2/
    tC

  # Move cursor to beginning of line
  s/([^\n]+)%\n/%\1\n/

  :D
    # Add one to each space on the line as long as counter is >0
    s/%([^ \n]* )(.*)1$/\1 %\2/
    tD

    # Counter is still >0; go back to beginning of line
    s/(^|\n)([^\n]+)%(.*1)$/\1%\2\3/
    tD

    # Counter is 0; move cursor to next line and branch to :B
    s/%([^\n]*)\n(.*)\n$/\1\n%\2/
    tB

:Q

# Remove cursor, any remaining 1s
s/%(.*)\n1*$/\1/

Це неймовірно, але коли я запускаю його за допомогою, gsed (GNU sed) 4.4я отримую gsed: -e expression #1, char 16: ":" lacks a label. Чи можете ви додати примітку про те, як саме ви її викликаєте? (Я використовую printf "%s\n%s" "$1" "$2" | gsed -r '<code here>';)
Дейв

@Dave Це працює для мене в GNU sed 4.2. Ось суть: gist.github.com/jrunning/91a7584d95fe10ef6b036d1c82bd385c Зверніть увагу, що сторінка TiO sed не схоже на -rпрапор, і саме тому посилання TiO вище переходить на сторінку bash.
Йорданія

Ах, я не помітив посилання TiO. Це зробить для мене; мати +1! На останньому прикладі є 2 невеликі помилки ("чорний звір"): він друкує другий-останній рядок на один символ короткий і пропускає остаточний !(хоча, оскільки я пропустив !зі списку можливих спеціальних символів, я не затримає проти цього).
Дейв

5

JavaScript (ES6), 147 байт

Вводиться як " (width)(text).

w=>F=(s,p=S=' ')=>(g=([c,...b],o='',h=c=='-')=>c?o[w-1]?c==S&&o+`
`+F(b):o[w+~h]?o+c+`
`+F(b):c>S?g(b,h?o:o+c):g(b,o+p)||g(b,o+p+c):o)(s)||F(s,p+S)

Спробуйте в Інтернеті!

Прокоментував

w =>                              // w = requested width
  F = (                           // F is a recursive function taking:
    s,                            //   s = either the input string (first iteration) or an
                                  //       array of remaining characters (next iterations)
    p =                           //   p = current space padding
    S = ' '                       //   S = space character
  ) => (                          //
    g = (                         // g is a recursive function taking:
      [c,                         //   c   = next character
          ...b],                  //   b[] = array of remaining characters
      o = '',                     //   o   = output for the current line
      h = c == '-'                //   h   = flag set if c is a hyphen
    ) =>                          //
      c ?                         // if c is defined:
        o[w - 1] ?                //   if the line is full:
          c == S &&               //     fail if c is not a space
          o + `\n` + F(b)         //     otherwise, append o + a linefeed and process the
                                  //     next line
        :                         //   else:
          o[w + ~h] ?             //     if this is the last character and c is a hyphen:
            o + c + `\n` + F(b)   //       append o + c + a linefeed and process the next
                                  //       line
          :                       //     else, we process the next character:
            c > S ?               //       if c is not a space:
              g(b, h ? o : o + c) //         append c if it's not a hyphen
            :                     //       else:
              g(b, o + p) ||      //         append either the current space padding
              g(b, o + p + c)     //         or the current padding and one extra space
      :                           // else:
        o                         //   success: return o
  )(s)                            // initial call to g() with s
  || F(s, p + S)                  // in case of failure, try again with a larger padding



1

Python 2 , 343 байт

W,T=input()
T+=' '
L,l=[],len
while T:
 p,r=0,''
 for i in range(l(T)):
  s=T[:i].replace('-','')
  if'-'==T[i]:s+='-'
  if T[i]in' -'and W-l(s)>=0:p,r=i,s
 R=r.split()
 if R:
  d,k=W-l(''.join(R)),0
  for j in range(d):
   R[k]+=' '
   k+=1
   if k==l(R)-1:k=0
  L+=[''.join(R)]
  T=T[p+1:]
print'\n'.join(L[:-1])
print' '.join(L[-1].split())

Спробуйте в Інтернеті!

The  input  is a block of text
containing possibly hyphenated
words.  For  each space/hyphen
position  p  the code computes
l(p)  the  length  of the line
induced  by  slipping the text
to this space/hyphen. Then the
code choses the position p for
which  the  length l(p) is the
closest  to  the given width W
(and  l(p)<=W).  If l(p)<W the
code  adds spaces  fairly  in-
between  the  words to achieve
the length W.

Хоча вхід може бути у будь-якому форматі, який вам подобається, він все одно повинен надходити з STDIN або параметрів. Див. За замовчуванням для вводу / виводу . Ми, як правило, не допускаємо, щоб "введення" було від попередньо призначених змінних.
mbomb007

Ви можете зберегти байт, виконавши print'\n'.join(L[:-1])замістьfor e in L[:-1]:print e
mbomb007

@ mbomb007 Ок, так, я зроблю необхідні зміни щодо дотримання вводу-виводу
mdahmoune
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.