Ritaglia ASCII Art Challenge


13

L'arte ASCII è divertente. I moderni editor di testo sono molto bravi a manipolare il testo. I moderni linguaggi di programmazione sono all'altezza del compito?

Un compito comune nella manipolazione dell'arte ASCII è ritagliare il testo in un rettangolo tra due caratteri. Questo è il compito che devi implementare in questa sfida.

Dettagli

Il tuo programma avrà 3 input:

  • il primo è il carattere "iniziale" del blocco, che segna l'angolo in alto a sinistra
  • il secondo è il carattere 'fine' del blocco, che segna l'angolo in basso a destra
  • il terzo è una forma di testo multilinea, una stringa, o un elenco di stringhe, o un nome file o altro

Il risultato sarà un testo multilinea (di nuovo, in uno dei formati sopra) ritagliato nel rettangolo tra gli input dati. Si noti che i primi due ingressi potrebbero non essere univoci.

Custodie per bordi

Le scatole devono sempre avere un volume di almeno 2, quindi questi:

()     (
       )

sono scatole ma queste:

)(     )      (
       (     )

non lo sono (con start = (e end = )).

L'input conterrà solo una casella. Pertanto, i caratteri di inizio e fine devono essere presenti solo una volta, a meno che non siano dello stesso carattere, nel qual caso devono apparire esattamente due volte.

Inoltre, ogni linea nell'input deve essere lunga almeno quanto la distanza dall'inizio di una linea al bordo destro della casella nell'input.

Non è necessario che il tuo programma gestisca input non validi; possono comportare comportamenti indefiniti.

Regole

Si applicano le regole tipiche del code-golf. Il codice più corto vince.

Esempi

Giorno soleggiato: start: ( end: ) input:

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

Produzione:

(but this text
is in a box  )

Nota anche lo stripping dello spazio orizzontale. Le colture d'arte ASCII sono 2d.

Giorno di pioggia: start: ( end: ) input:

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

Produzione:

(
)

Stesso inizio / fine: start: / end: / input:

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

Produzione:

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

Inserimento non valido: start: ( end: ) input:

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

Ingresso 2 non valido: start: ( end: ) input:

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

Che dire di una scatola valida con una linea esterna più corta della scatola?
seadoggie01

1
input chiarito, anche non valido
LambdaBeta,

quale dovrebbe essere il risultato in caso di input non valido? o sono menzionati in modo che non debbano essere curati?
Uriel,

1
Il risultato è molto simile al comportamento indefinito in C, non ti preoccupare, tutto va bene.
LambdaBeta,

Questa è una brutta piccola sfida: bel lavoro!
seadoggie01,

Risposte:


15

Vim, 16 , 12 byte / sequenze di tasti

#<C-v>Nj*yggVGp

Provalo online! nell'interprete V.

I moderni editor di testo sono molto bravi a manipolare il testo. I moderni linguaggi di programmazione sono all'altezza del compito?

Scommetto che i vecchi editor di testo sono ancora meglio! : D

Anche se non è necessario, questa risposta funziona con entrambi gli input "non validi" forniti, in uscita

 rectangular (
) which is ill

e

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

Spiegazione:

#               " 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
Per inciso, questo è esattamente il caso d'uso che stavo facendo per spingermi a scrivere questa sfida. Ho avuto la mia macro q /\/<cr><c-v>nygv$o0dpo qualcosa del genere per troppo tempo :)
LambdaBeta,

2
Sì, rettangolare è il più malato !
AdmBorkBork,

6

Gelatina , 13 byte

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

Un collegamento diadico che accetta un elenco di caratteri di inizio e fine a sinistra e un elenco di righe (come elenchi di caratteri) a destra che produce un elenco di righe (come elenchi di caratteri).

Provalo online! (programma completo - se gli input sono Python validi richiederanno la quotazione di stringhe Python.)

Come?

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

Ad esempio, con left = ['a', 'b']e right (come un elenco di elenchi di caratteri - le linee):

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

=€produce un elenco di due elenchi di elenchi (il primo esegue 'a'=, il secondo 'b'=):

00000000         00000000
00100000         00000000
00000000    ,    00000000
00000000         00000100
00000000         00000000

sommando questo si ottiene un unico elenco di elenchi (sommando l'elemento saggio):

00000000
00100000
00000000
00000100
00000000

ŒṪpoi ci dà gli indici multidimensionali (1-indicizzati) dei non zeri, [[2,3],[4,6]]- cioè [[top,left],[bottom,right]].

r/quindi esegue ciò [2,3]r[4,6]che, dal momento che rvettorializza, è come [2r4, 3r6]valutare [[2,3,4],[3,4,5,6]]- cioè [rows,columns].

,þ/quindi esegue [2,3,4],þ[3,4,5,6]dove þè un'istruzione di poduct esterno ed ,è coppia. Questo produce tutti i [row,column]valori per colonna, in questo caso:

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

Vogliamo questi per riga, quindi Zviene utilizzato per trasporre questo a:

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

Infine, œịtorna agli indici nelle righe di input:

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

Vale la pena notare che quando entrambi i personaggi delimitati sono uguali =€identifica entrambi due volte ma SŒṪfinisce per fare la cosa giusta, poiché 2è vero, ad esempio con ['a','a']:

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

... Ho letto la spiegazione, ma ancora non la capisco. o_o Potresti aggiungere un esempio funzionato, forse?
DLosc,

Incentivazione: accetterò la tua risposta se è completamente spiegata. :)
LambdaBeta,

1
@DLosc - fatto, spero che sia d'aiuto.
Jonathan Allan,

@LambdaBeta - la risposta V è più breve.
Jonathan Allan,

... errare anche la risposta di Vim.
Jonathan Allan,

5

APL (Dyalog) , 38 30 byte

4 byte salvati grazie a @EriktheOutgolfer

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

Provalo online!


troppo complicato. potresti accettare una matrice anziché un vettore di vettori, trovare le due posizioni con ⍸matrix∊separatorse prendere / rilasciare con esse
ngn

(⍸a=⎕)↓(1+⍸a=⎕)↑a←⎕con⎕io←0
ngn il

@ngn OP ha detto che il numero di caratteri differisce tra le righe, quindi ho supposto che l'input dovesse essere vettoriale prima dell'elaborazione. Anche così, ho bisogno delle parti di selezione (prima e ruotate) nel caso in cui il delimitatore venga visualizzato alcune volte (vedi terzo caso di test), ma immagino che la goccia tagli qualche byte, quindi grazie! Aggiornerò una volta arrivato sul PC
Uriel

oops ... Mi sono dimenticato del terzo caso, scusa. Quindi forse: ⊃{⌽⊖⍵↓⍨⊃⍸⍺=⍵}/⎕⎕⎕(sic, con 3 quad di coda) che è ancora più corto. O ... ⎕⎕(↑⎕)se non è consentita una matrice premiscelata.
ngn,

3

Gelatina , 14 byte

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

Provalo online!


Ho provato a eseguire il codice su alcuni degli altri esempi, ma ho avuto solo un arresto anomalo. È un bug o sto solo facendo qualcosa di sbagliato?
Ilmari Karonen,

@IlmariKaronen Non hai citato correttamente il secondo argomento (non lo hai menzionato nel post); avvolgerlo tra virgolette singole o doppie. Nel modo in cui l'hai invocato, il secondo argomento è una tupla ( ()) vuota (Python ), non '()'. Se è analizzabile, deve essere quotato, tuttavia, my //non ha bisogno di essere quotato (operatore di divisione intera senza operandi? Hm ...).
Erik the Outgolfer,

@IlmariKaronen "Penso" che ()sia interpretato da Jelly come una specie di personaggio speciale. La maggior parte delle coppie di personaggi provo a lavorare. Mi piacerebbe sapere cosa pensano le persone che hanno più familiarità con Jelly. EDIT: ninja-ed di erik the outgolfer
LambdaBeta,


3

Python 2 , 130 byte

def f(s,e,t):
 a=[(i,l.find(c))for i,l in enumerate(t)for c in s+e if c in l];r,c,R,C=a[0]+a[-1]
 for l in t[r:R+1]:print l[c:C+1]

Provalo online!


2

Tela , 37 byte

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

Provalo qui!

36 byte per ottenere le coordinate dei caratteri (e convertirli in x, y, w, h perché è quello che serve) e 1 byte per ottenere la sottosezione. Deve esserci un approccio migliore


2

JavaScript (ES6), 98 byte

Accetta input come due numeri interi e una matrice di stringhe. Restituisce una matrice di stringhe.

(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))

Provalo online!

Commentate

( 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 e map ?! Costruire un nuovo array con reduceo una soluzione ricorsiva non funzionerebbe più breve? Sul telefono, in fondo al pub o ci proverei io stesso.
Shaggy,

@Shaggy Probabilmente c'è probabilmente un modo più breve, ma penso che questo metodo sia destinato a usare 2 passaggi: il 2 ° ciclo non può iniziare prima che il 1 ° termina ed entrambi Xe Ysono noti per certo.
Arnauld,

2

Java 10, 204 byte

(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);}

Modifica l'input-array invece di restituirne uno nuovo per salvare i byte. Ciò significa che le linee rimosse diventano ""invece, tuttavia. Se ciò non è consentito, lo cambierò.

Provalo online.

Spiegazione:

(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

Per esempio:

Con gli ingressi start = "(", end = ")"elines =

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

il primo loop lo ritaglierà in alto a sinistra, cambiandolo in questo:

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

il secondo loop lo ritaglierà in basso a destra, cambiandolo in questo:

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

1

Retina 0.8.2 , 110 byte

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

Provalo online! Spiegazione:

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

Elimina le righe di input che precedono la prima riga del riquadro.

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

Se il carattere iniziale si trova nella colonna di sinistra dell'input, eliminarlo.

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

Se il carattere iniziale non è stato ancora eliminato, sposta tutte le colonne di input lasciate di una e ripeti dall'inizio.

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

Elimina il carattere finale e tutto nell'input dopo il carattere finale.

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

Tronca tutte le righe alla lunghezza della riga successiva. Funziona contando tutti i caratteri tranne uno su ogni riga, quindi tentando di abbinare fino a quel numero di caratteri sulla riga successiva; se ciò ha esito positivo, la seconda riga è più corta, quindi l'ultimo carattere viene eliminato e il ciclo si ripete.


0

C (gcc) , 237 byte

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;}}

Provalo online!

Sono sicuro al 99% che questo può essere abbreviato usando una sorta di funzione di aiuto per trovare l'indice orizzontale e il puntatore a un personaggio, poiché viene ripetuto due volte. Purtroppo non riesco a trovare un modo abbastanza breve per farlo, potrei riprovare più tardi se trovo il tempo.

Descrizione

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
Ancora meglio: 219 byte
Zacharý

0

Stax , 15 byte

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

Esegui ed esegui il debug

Prende il set di caratteri delimitatore casella (1 o 2) sulla prima riga di input. Il resto delle linee è il corpo di input.

Disimballato, non golfato e commentato, sembra così.

            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

Esegui questo

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.