Crop 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
Результат очень похож на неопределенное поведение в C, не беспокойтесь об этом, все идет.
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
Между прочим, это именно тот вариант использования, который я использовал, чтобы побудить меня написать этот вызов. У меня был макрос q как- /\/<cr><c-v>nygv$o0dpто слишком долго :)
LambdaBeta

2
Да, прямоугольник самый плохой !
AdmBorkBork

6

Желе , 13 байт

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

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

Попробуйте онлайн! (полная программа - если входные данные являются допустимыми Python, они требуют цитирования строк Python.)

Как?

=€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)

Как пример, с left = ['a', 'b']и right (как список списков символов - строки):

--------
--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]которые, так как rvectorises, подобна [2r4, 3r6], вычисляемая [[2,3,4],[3,4,5,6]]- то есть [rows,columns].

,þ/затем выполняет [2,3,4],þ[3,4,5,6]где þинструкция external-poduct и ,пара. Это дает все [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

... Я прочитал объяснение, но я все еще не понимаю его. о_о Не могли бы вы добавить работающий пример, возможно?
DLosc

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

1
@DLosc - готово, надеюсь, это поможет.
Джонатан Аллан

@LambdaBeta - ответ V короче.
Джонатан Аллан

... даже ответ Vim.
Джонатан Аллан

5

APL (Dyalog) , 38 30 байт

4 байта сохранены благодаря @EriktheOutgolfer

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

Попробуйте онлайн!


слишком сложно. Вы можете принять матрицу вместо вектора векторов, найти две позиции с помощью ⍸matrix∊separatorsи выполнить их с помощью take / drop
ngn

(⍸a=⎕)↓(1+⍸a=⎕)↑a←⎕с⎕io←0
нгн

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

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

3

Желе , 14 байт

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

Попробуйте онлайн!


Я попытался запустить ваш код на некоторых других примерах, но потерпел крах. Это ошибка или я просто делаю что-то не так?
Илмари Каронен

@IlmariKaronen Вы не правильно процитировали второй аргумент (не упомянули об этом в посте); оберните это в одинарные или двойные кавычки. Как вы и вызывали, вторым аргументом является пустой (Python) кортеж ( ()), а не '()'. Если он может быть разобран, его нужно заключить в кавычки, однако //не нужно заключать в кавычки (оператор целочисленного деления без операндов? Хм ...).
Эрик Outgolfer

@IlmariKaronen Я «думаю», что ()Джелли просто интерпретирует это как особый характер. Большинство пар персонажей я стараюсь работать. Мне бы очень хотелось услышать, что думают люди, знакомые с желе. РЕДАКТИРОВАТЬ: ниндзя-ред Эрик 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 - й цикл не может начаться до 1 один прекращается , и как 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

Stax , 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.