Обрізати ASCII Art Challenge


13

Мистецтво ASCII - це весело. Сучасні текстові редактори дуже добре маніпулюють текстом. Чи доречні сучасні мови програмування?

Одне поширене завдання в мистецтві ASCII маніпуляції - обрізати текст у прямокутник між двома символами. Це завдання, яке ви повинні виконати в цьому виклику.

Деталі

Ваша програма займе 3 входи:

  • Перший - символ "старту" блоку - позначення верхнього лівого кута
  • друге - символ кінця блоку - позначення правого нижнього кута
  • третя - деяка форма багаторядкового тексту, або рядок, або список рядків, імені файлу, або будь-якого іншого

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

Корпусні кромки

Ящики завжди повинні мати об'єм не менше 2. Отже, такі:

()     (
       )

є коробки, але це:

)(     )      (
       (     )

не є (з початком = (і кінцем = )).

Вхід буде містити лише одне поле. Таким чином, початкові та кінцеві символи повинні відбуватися лише один раз, якщо тільки вони не є одним і тим же символом, в цьому випадку вони повинні відбуватися рівно двічі.

Крім того, кожен рядок на вході повинен бути не менше, ніж відстань від початку рядка до правого краю поля у вводі.

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

Правила

Застосовуються типові правила коду-гольфу. Найкоротший код виграє.

Приклади

Сонячний день: start: ( end: ) input:

This is some text
. (but this text
  is in a box  ).
So only it is important.

Вихід:

(but this text
is in a box  )

Зверніть увагу і на зачистку горизонтального простору. Художні культури ASCII - це 2d.

Дощовий день: start: ( end: ) input:

This is some text (
But is that even  )
really a box?

Вихід:

(
)

Той самий початок / кінець: start: / end: / input:

Oh, I get how this could be useful
 /----------------------------\
 | All this text is in a box! |
 \----------------------------/

Вихід:

/----------------------------\
| All this text is in a box! |
\----------------------------/

Неправильні дані: start: ( end: ) input:

Boxes are rectangular ( so this has
0 volume ) which is illegal.

Недійсний вхід 2: start: ( end: ) input:

(The lines must already be square 
so this line that is too short
relative to this end, is illegal)

А як із дійсним полем із зовнішньою лінією, яка коротша, ніж у полі?
seadoggie01

1
уточнено, також недійсний вхід
LambdaBeta

яким повинен бути результат у випадку недійсного введення? або про них згадують, тож про них не доведеться піклуватися?
Уріель

1
Результат схожий на невизначену поведінку у С, не хвилюйтеся з цього приводу, все що завгодно.
LambdaBeta

Це неприємний маленький виклик: приємна робота!
seadoggie01

Відповіді:


15

Vim, 16 , 12 байт / натискання клавіш

#<C-v>Nj*yggVGp

Спробуйте в Інтернеті! у V перекладачі

Сучасні текстові редактори дуже добре маніпулюють текстом. Чи доречні сучасні мови програмування?

Гадаю, що старі текстові редактори ще краще! : D

Незважаючи на те, що це не обов'язково, ця відповідь працює з обома даними "недійсних" входів, виводячи дані

 rectangular (
) which is ill

і

(The lines must already be square
so this line that is too short
relative to this end, is illegal)

Пояснення:

#               " Move backward to the previous occurrence of the word (or in this case, character) under the cursor
 <C-v>          " Start a visual block selection
      N         " Go to the next occurrence of the last searched term (guaranteed to be line 1)
       j        " Move down a line
        *       " Move forward to the next occurrence of the character under the cursor
         y      " Yank (copy) the whole visually selected block
          gg    " Go to line 1
            VG  " Select every line
              p " And paste what we last copied over it, deleting the whole buffer and replacing it with the block

1
До речі, саме такий випадок, який я робив, запропонував мені написати цей виклик. Я /\/<cr><c-v>nygv$o0dpзанадто довго мав свій макрос q або щось подібне :)
LambdaBeta

2
Так, прямокутний - це найновіший !
AdmBorkBork

6

Желе , 13 байт

=€SŒṪr/,þ/Zœị

Дьядичне посилання, що приймає список початкових і кінцевих символів зліва та список рядків (як списки символів) праворуч, що дає список рядків (як списки символів).

Спробуйте в Інтернеті! (повна програма - якщо введення дійсні Python, вони вимагатимуть Python-string-quoting.)

Як?

=€SŒṪr/,þ/Zœị - Link: [start, stop], lines
 €            - for each (of [start, stop]):
=             -   equals? (vectorises across the lines)
  S           - sum (vectorises)
   ŒṪ         - multi-dimensional truthy (i.e. non-zero) indices
      /       - reduce by:
     r        -   inclusive range (vectorises)
         /    - reduce by:
        þ     -    outer product with:
       ,      -       pair
          Z   - transpose
           œị - multi-dimensional index-into (the lines)

Наприклад, зліва = ['a', 'b']і справа (як список списків символів - рядки):

--------
--a+++--
--++++--
--+++b--
--------

=€виходить список із двох списків списків (перший виконує 'a'=, другий 'b'=):

00000000         00000000
00100000         00000000
00000000    ,    00000000
00000000         00000100
00000000         00000000

підсумовуючи це, виходить єдиний список списків (підсумовуючи елементи):

00000000
00100000
00000000
00000100
00000000

ŒṪто дає нам (1-індексований) багатовимірні показники ненульових значень, [[2,3],[4,6]]- тобто [[top,left],[bottom,right]].

r/потім виконує [2,3]r[4,6]яке, оскільки rвекторизація, схоже [2r4, 3r6], оцінюючи на [[2,3,4],[3,4,5,6]]- тобто [rows,columns].

,þ/потім виконує, [2,3,4],þ[3,4,5,6]де þє інструкція зовнішнього піддукта і ,пара. У цьому випадку виходять усі [row,column]значення за стовпцем:

[[[2,3],[3,3],[4,3]],
 [[2,4],[3,4],[4,4]],
 [[2,5],[3,5],[4,5]],
 [[2,6],[3,6],[4,6]]]

Ми хочемо, щоб вони були за рядками, тому Zвикористовується для перенесення цього на:

[[[2,3],[2,4],[2,5],[2,6]],
 [[3,3],[3,4],[3,5],[3,6]],
 [[4,3],[4,4],[4,5],[4,6]]]

Нарешті œịіндексується назад у рядки введення:

a+++
++++
+++b

Варто зазначити, що коли обоє обмежувальних символів однакові, =€ідентифікуються обидва рази, але в SŒṪкінцевому підсумку роблять правильно, оскільки 2це неправда, наприклад з ['a','a']:

--------         00000000   00000000        00000000
--a+++--         00100000   00100000        00200000
--++++--  =€ ->  00000000 , 00000000  S ->  00000000  ŒṪ ->  [[2,3],[4,6]]
--+++a--         00000100   00000100        00000020
--------         00000000   00000000        00000000

... Я читав пояснення, але все ще не розумію. o_o Чи не могли б ви додати відпрацьований приклад?
DLosc

Стимулювання: я прийму вашу відповідь, якщо вона буде повністю пояснена. :)
LambdaBeta

1
@DLosc - готово, сподіваюся, що це допоможе.
Джонатан Аллан

@LambdaBeta - відповідь V коротша.
Джонатан Аллан

... навіть помилитися з відповіддю Віма.
Джонатан Аллан

5

APL (Dyalog) , 38 30 байт

4 байти збережено завдяки @EriktheOutgolfer

(1-⍨w-⍨⊃⍸⎕=s)↑(w←∊⊃⌽⍸⎕=s)↑s←↑⎕

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


занадто складний. ви можете прийняти матрицю замість векторів, знайти дві позиції з ⍸matrix∊separators, і
займіть

(⍸a=⎕)↓(1+⍸a=⎕)↑a←⎕з⎕io←0
пн.

@ngn OP зазначила, що кількість символів відрізняється між рядками, тому я припустив, що вхід повинен бути векторним перед обробкою. Незважаючи на це, мені потрібні частини вибору (спочатку та обертання), якщо роздільник відображається кілька разів (див. Третій тестовий випадок), але я думаю, що крапля скоротить кілька байт, тож спасибі! Я
Uriel

ой ... я забув про третій випадок, вибач. Тоді можливо: ⊃{⌽⊖⍵↓⍨⊃⍸⍺=⍵}/⎕⎕⎕(наприклад, з трьома трьома квадратиками), що ще коротше. Або ... ⎕⎕(↑⎕)якщо попередньо змішана матриця не дозволена.
ngn

3

Желе , 14 байт

œẹⱮẎQr/Ṛṭþ/œị⁸

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


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

@IlmariKaronen Ви не цитували другий аргумент належним чином (не згадували про це у публікації); загортайте його в одинарні чи подвійні лапки. Те, як ви його викликали, другий аргумент - це порожній (Python) кортеж ( ()), а не '()'. Якщо це можливо для розбору, його потрібно цитувати, однак, моє //не потрібно цитувати (оператор цілого числа без операндів? Hm ...).
Ерік Аутгольфер

@IlmariKaronen Я "думаю", що ()саме трактується Джеллі як якийсь особливий персонаж. Більшість пар персонажів я намагаюся працювати. Я хотів би почути, що думають люди, більш знайомі з Jelly. EDIT: ninja-ed від erik the outgolfer
LambdaBeta



2

Полотно , 37 байт

{³⁴⁰;x≡‽┐
X⁸)J╵⁶;┤ω┤⁵X⁶⁸⁰K├;┐┤└∔┘┘∔;@

Спробуйте тут!

36 байт для отримання координат символів (та перетворення їх у x, y, w, h, тому що це потрібно) та 1 байт для отримання підрозділу. Повинен бути кращий підхід


2

JavaScript (ES6), 98 байт

Вводить дані як два цілих числа та масив рядків. Повертає масив рядків.

(x,y,a,X=Y=0)=>a.filter(s=>!Y&&(Y=-~s.indexOf(y,X?X-1:X=-~s.indexOf(x)),X)).map(s=>s.slice(X-1,Y))

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

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

( x,                          // x = start character
  y,                          // y = end character
  a,                          // a[] = array of strings
  X =                         // X = position of x, plus 1
  Y = 0                       // Y = position of y, plus 1
) =>                          //
  a.filter(s =>               // for each string s in a[]:
    !Y &&                     //   reject this string if Y is non-zero
    (                         //   otherwise, use the 2nd condition:
      Y = -~s.indexOf(        //     update Y:
        y,                    //       by looking for y in s
        X ?                   //       if X is non-zero:
          X - 1               //         start the search at X - 1
        :                     //       else:
          X = -~s.indexOf(x)  //         update X and start the search at X
      ),                      //     end of Y update
      X                       //     keep this string if X is non-zero
    )                         //   end of 2nd condition
  )                           // end of filter()
  .map(s =>                   // for each remaining string s:
    s.slice(X - 1, Y)         //   remove left and right characters outside the box
  )                           // end of map()

filter і map ?! Чи не складеться створення нового масиву з reduceрекурсивним рішенням або коротше? На мені телефон, вниз в паб або я б сам поїхав.
Кудлатий

@Shaggy Мабуть, мабуть, коротший шлях справді, але я думаю, що цей метод приречений на використання 2 проходів: 2-й цикл не може починатися до того, як перший закінчується, і обидва, Xі Yвони точно відомі.
Арнольд

2

Java 10, 204 байти

(s,e,a)->{int b=-1,i=0;for(;i<a.length;i++)a[i]=(b=b<0?a[i].indexOf(s):b)<0|a[i].length()<b?"":a[i].substring(b);for(b=-1;i-->0;)a[i]=(b=b<0?a[i].indexOf(e):b)<0|a[i].length()<b?"":a[i].substring(0,b+1);}

Змінює вхідний масив замість повернення нового для збереження байтів. Це все-таки означає, що ""замість цього стають видалені лінії . Якщо це заборонено, я його зміню.

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

Пояснення:

(s,e,a)->{                 // Method with 2 Strings & String-array parameters and no return
  int b=-1,                //  Boundaries-integer, starting at -1
  i=0;for(;i<a.length;i++) //  Loop `i` in the range [0, amountOfLines)
    a[i]=                  //   Change the `i`th line in the array to:
      (b=b<0?              //    If `b` is -1:
          a[i].indexOf(s)  //     Set `b` to the index of `s` in the current line
                           //     (which is still -1 if it's not found)
         :                 //    Else (starting index already found)
          b                //     Leave `b` unchanged
      )<0                  //    Then, if `b` is -1,
         |a[i].length()<b? //    or the current line-length is too short:
       ""                  //     Remove the current line
      :                    //    Else:
       a[i].substring(b);  //     Shorten the line by removing every character before `b`
  for(b=-1;                //  Reset `b` to -1
      i-->0;)              //  Loop `i` in the range (amountOfLines, 0]
    a[i]=                  //  Change the `i`th line in the array to:
       (b=b<0?a[i].indexOf(e):b)<0|a[i].length()<b?"":
                           //   Similar as above (with end `e` instead of start `s`),
         a[i].substring(0,b+1);}
                           //   except we remove every character after `b` this time

Наприклад:

Із входами start = "(", end = ")"іlines =

["This is some text",
 ". (but this text",
 "  is in a box  ).",
 "So only it is important."]

перший цикл обріже його вгорі та вліво, змінивши його на це:

["",
 "(but this text",
 "is in a box  ).",
 " only it is important."]

другий цикл обріже його внизу і вправо, змінивши його на це:

["",
 "(but this text",
 "is in a box  )",
 ""]

1

Сітківка 0,8.2 , 110 байт

^((.)¶.)(.*¶)+(.*\2)
$1¶$4
^(.)(¶.¶\1)
$2
}s`(?<=^.¶.+)¶.
¶
s`^¶(.)¶(.*\1).*
$2
+m`^((.)+).¶((?<-2>.)+)$
$1¶$3

Спробуйте в Інтернеті! Пояснення:

^((.)¶.)(.*¶)+(.*\2)
$1¶$4

Видаліть рядки введення, що передують першому рядку поля.

^(.)(¶.¶\1)
$2

Якщо символ запуску знаходиться в лівій колонці вводу, видаліть його.

}s`(?<=^.¶.+)¶.
¶

Якщо символ запуску ще не видалено, змістіть усі вхідні стовпці, залишені одним, та повторіть з початку.

s`^¶(.)¶(.*\1).*
$2

Видаліть кінцевий символ та все, що знаходиться у вводі після символу кінця.

+m`^((.)+).¶((?<-2>.)+)$
$1¶$3

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


0

C (gcc) , 237 байт

f(c,r,o,p)char*p,*c;{char*_=strchr(p,r),*a,b;*_=0;a=strrchr(p,10);a=(a?a:p);*_=r;r=_-a;p=a;_=strrchr(p,o);*_=0;a=strrchr(p,10);a=(a?a:p);*_=o;o=_-a+1;_[1]=0;for(_=p;_;_=strchr(_+1,10)){b=_[o];_[o]=0;strcat(c,_+r);strcat(c,"\n");_[o]=b;}}

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

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

Опис

f(c,r,o,p)char*p,*c;{
    char*_=strchr(p,r),*a,b;         // find opening char (and declare vars)
    *_=0;a=strrchr(p,10);            // find \n before it
    a=(a?a:p);                       // deal with single line inputs
    *_=r;r=_-a;                      // save left margin width in r
    p=a;                             // crop everything before opening line

    _=strchr(p,o);                   // find closing char
    *_=0;a=strrchr(p,10);            // find \n before it
    a=(a?a:p);                       // deal with single line inputs
    *_=o;o=_-a+1;                    // save width in o
    _[1]=0;                          // crop everything after closing char
    for(_=p;_;_=strchr(_+1,10)){       // for each line
        b=_[o];_[o]=0;
        strcat(c,_+r);
        strcat(c,"\n");
        _[o]=b;
    }
}

1
Ще краще: 219 байт
Zacharý

0

Стакс , 15 байт

╛↨½╝v∞░W╧)╗Ö≈☼k

Запустіть і налагоджуйте його

Він займає набір символів роздільника поля (1 або 2) у першому рядку введення. Решта рядків - це вхідне тіло.

Розпакований, неозорений та коментований, це виглядає приблизно так.

            first line of input is the delimiter characters
dL          discard the first line of input and listify the rest into an array
{           begin block for iteration
  Mr        rotate matrix 90 degrees
  {         begin block for while loop
    ch      copy first row of block
    y|&C    if it insersects with the first line of input, break iteration
    D       drop the first line
  W         do-while loop until break
}4*         execute block 4 times
m           display result lines

Виконати цей

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