Ernte ASCII Art Challenge

13

ASCII-Kunst macht Spaß. Moderne Texteditoren können sehr gut Text bearbeiten. Sind moderne Programmiersprachen der Aufgabe gewachsen?

Eine häufige Aufgabe bei der Bearbeitung von ASCII-Grafiken besteht darin, Text auf ein Rechteck zwischen zwei Zeichen zuzuschneiden. Dies ist die Aufgabe, die Sie in dieser Herausforderung umsetzen müssen.

Einzelheiten

Ihr Programm wird 3 Eingaben annehmen:

  • Das erste ist das 'Start'-Zeichen des Blocks - es markiert die obere linke Ecke
  • Das zweite ist das 'Ende'-Zeichen des Blocks - es markiert die untere rechte Ecke
  • Das dritte ist eine Form von mehrzeiligem Text, entweder eine Zeichenfolge oder eine Liste von Zeichenfolgen oder ein Dateiname oder was auch immer

Das Ergebnis ist mehrzeiliger Text (ebenfalls in einem der oben genannten Formate), der auf das Rechteck zwischen den angegebenen Eingaben zugeschnitten wird. Beachten Sie, dass die ersten beiden Eingänge möglicherweise nicht eindeutig sind.

Edge-Fälle

Boxen müssen immer ein Volumen von mindestens 2 haben.

()     (
       )

sind Boxen, aber diese:

)(     )      (
       (     )

sind nicht (mit start = (und end = )).

Die Eingabe enthält nur eine Box. Daher dürfen Start- und Endzeichen nur einmal vorkommen, es sei denn, sie sind dasselbe Zeichen. In diesem Fall müssen sie genau zweimal vorkommen.

Außerdem muss jede Zeile in der Eingabe mindestens so lang sein wie der Abstand zwischen dem Beginn einer Zeile und dem rechten Rand des Felds in der Eingabe.

Ihr Programm muss keine ungültigen Eingaben verarbeiten. Sie können zu undefiniertem Verhalten führen.

Regeln

Es gelten die typischen Code-Golf-Regeln. Kürzester Code gewinnt.

Beispiele

Sonniger Tag: start: ( end: ) input:

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

Ausgabe:

(but this text
is in a box  )

Beachten Sie auch das Entfernen des horizontalen Raums. ASCII-Kunstpflanzen sind 2d.

Regnerischen Tag: start: ( end: ) input:

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

Ausgabe:

(
)

Gleicher Anfang / Ende: start: / end: / input:

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

Ausgabe:

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

Ungültige Eingabe: start: ( end: ) input:

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

Ungültige Eingabe 2: start: ( end: ) input:

(The lines must already be square 
so this line that is too short
relative to this end, is illegal)
LambdaBeta
quelle
Was ist mit einer gültigen Box mit einer Linie außerhalb, die kürzer als die Box ist?
Seadoggie01
1
geklärt, auch ungültige Eingabe
LambdaBeta
was soll das ergebnis bei einer ungültigen eingabe sein? oder werden sie erwähnt, damit sie nicht gepflegt werden müssen?
Uriel
1
Das Ergebnis ist ähnlich wie undefiniertes Verhalten in C, keine Sorge, alles ist möglich.
LambdaBeta
Dies ist eine böse kleine Herausforderung: gute Arbeit!
Seadoggie01

Antworten:

15

Vim, 16 , 12 Bytes / Tastenanschläge

#<C-v>Nj*yggVGp

Probieren Sie es online! im V-Interpreter

Moderne Texteditoren können sehr gut Text bearbeiten. Sind moderne Programmiersprachen der Aufgabe gewachsen?

Ich wette, alte Texteditoren sind noch besser! : D

Auch wenn dies nicht unbedingt der Fall sein muss, funktioniert diese Antwort mit beiden "ungültigen" Eingaben, die ausgegeben werden

 rectangular (
) which is ill

und

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

Erläuterung:

#               " 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
DJMcMayhem
quelle
1
Dies ist übrigens genau der Anwendungsfall, den ich gemacht habe, um mich zum Schreiben dieser Herausforderung aufzufordern. Ich hatte mein Q-Makro als /\/<cr><c-v>nygv$o0dpoder so etwas viel zu lange :)
LambdaBeta
2
Ja, rechteckig ist das krankste !
AdmBorkBork
6

Gelee , 13 Bytes

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

Ein dyadischer Link, der eine Liste von Start- und Endzeichen auf der linken Seite und eine Liste von Zeilen (als Listen von Zeichen) auf der rechten Seite akzeptiert, die eine Liste von Zeilen (als Listen von Zeichen) ergibt.

Probieren Sie es online!(Vollständiges Programm - Wenn Eingaben in Python gültig sind, müssen sie in Python-Zeichenfolgen angegeben werden.)

Wie?

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

Zum Beispiel mit left = ['a', 'b']und right (als Liste von Zeichenlisten - die Zeilen):

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

=€ergibt eine Liste von zwei Listen von Listen (die erste führt 'a'=, die zweite 'b'=):

00000000         00000000
00100000         00000000
00000000    ,    00000000
00000000         00000100
00000000         00000000

Wenn Sie dies summieren, erhalten Sie eine einzelne Liste von Listen (elementweise summieren):

00000000
00100000
00000000
00000100
00000000

ŒṪdann gibt uns die (1-indizierten) mehrdimensionalen Indizes der Nicht-Nullen, [[2,3],[4,6]]dh [[top,left],[bottom,right]].

r/dann führt [2,3]r[4,6]das, da rvektorisiert, ist wie das [2r4, 3r6]Auswerten zu [[2,3,4],[3,4,5,6]]- dh [rows,columns].

,þ/führt dann aus, [2,3,4],þ[3,4,5,6]wo þeine äußere Produktanweisung ist und ,ist Paar. Dies ergibt alle [row,column]Werte pro Spalte, in diesem Fall:

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

Wir wollen diese nach Zeilen aufteilen, daher Zwird dies verwendet, um Folgendes zu transponieren:

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

Schließlich œịzurück Indizes in den Eingangsleitungen:

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

Es ist erwähnenswert, dass, wenn beide Begrenzungszeichen gleich =€sind, beide zweimal identifiziert werden, aber SŒṪdas Richtige getan wird, da dies 2wahr ist, zB mit ['a','a']:

--------         00000000   00000000        00000000
--a+++--         00100000   00100000        00200000
--++++--  =€ ->  00000000 , 00000000  S ->  00000000  ŒṪ ->  [[2,3],[4,6]]
--+++a--         00000100   00000100        00000020
--------         00000000   00000000        00000000
Jonathan Allan
quelle
... Ich habe die Erklärung gelesen, aber ich verstehe sie immer noch nicht. o_o Könnten Sie vielleicht ein Beispiel hinzufügen?
DLosc
Incentivierung: Ich nehme Ihre Antwort an, wenn sie vollständig erklärt ist. :)
LambdaBeta
1
@ DLosc - fertig, hoffe es hilft.
Jonathan Allan
@ LambdaBeta - die V-Antwort ist kürzer.
Jonathan Allan
... irre die Vim Antwort sogar.
Jonathan Allan
5

APL (Dyalog) , 38 30 Bytes

4 Bytes gespart dank @EriktheOutgolfer

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

Probieren Sie es online!

Uriel
quelle
zu kompliziert. Sie könnten eine Matrix anstelle eines Vektors von Vektoren akzeptieren, die beiden Positionen mit ⍸matrix∊separatorsfinden und mit ihnen nehmen / fallen lassen
ngn
(⍸a=⎕)↓(1+⍸a=⎕)↑a←⎕mit⎕io←0
ngn
@ngn OP die Anzahl der Zeichen unterscheidet sich zwischen den Zeilen, so dass ich davon ausging, dass die Eingabe vor der Verarbeitung ein Vektor sein sollte. Trotzdem brauche ich die Auswahlteile (zuerst und drehen), falls der Begrenzer ein paar Mal angezeigt wird (siehe dritter Testfall), aber ich denke, der Drop schneidet ein paar Bytes, also danke! Ich werde ein Update durchführen, sobald ich auf dem PC bin
Uriel
Hoppla ... Ich habe den dritten Fall vergessen, sorry. Dann vielleicht: ⊃{⌽⊖⍵↓⍨⊃⍸⍺=⍵}/⎕⎕⎕(sic, mit 3 nachgestellten Quads) was noch kürzer ist. Oder ... ⎕⎕(↑⎕)wenn eine vorgemischte Matrix nicht erlaubt ist.
14.
3

Gelee , 14 Bytes

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

Probieren Sie es online!

Erik der Outgolfer
quelle
Ich habe versucht, Ihren Code in einigen anderen Beispielen auszuführen, bin aber nur abgestürzt. Ist das ein Fehler oder mache ich nur etwas falsch?
Ilmari Karonen
@IlmariKaronen Sie haben das zweite Argument nicht richtig zitiert (haben das im Beitrag nicht erwähnt); Schließen Sie es in einfache oder doppelte Anführungszeichen ein. So wie Sie es aufgerufen haben, ist das zweite Argument ein leeres (Python) Tupel ( ()), nicht '()'. Wenn es syntaktisch analysierbar ist, muss es in Anführungszeichen gesetzt werden. My //muss jedoch nicht in Anführungszeichen gesetzt werden (Operator für ganzzahlige Teilung ohne Operanden? Hm ...).
Erik der Outgolfer
@IlmariKaronen Ich "denke", dass ()Jelly das nur als eine Art Sonderzeichen interpretiert. Die meisten Zeichenpaare versuche ich zu arbeiten. Ich würde gerne hören, was die Leute, die mit Jelly vertraut sind, denken. EDIT: Ninja-Ed von Erik der Outgolfer
LambdaBeta
OK, ja, das funktioniert.
Ilmari Karonen
3

Python 2 , 130 Bytes

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]

Probieren Sie es online!

TFeld
quelle
2

Canvas , 37 Byte

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

Probieren Sie es hier aus!

36 Bytes zum Abrufen der Koordinaten der Zeichen (und zum Konvertieren in x, y, w, h, da dies erforderlich ist) und 1 Byte zum Abrufen des Unterabschnitts. Es muss einen besseren Ansatz geben

dzaima
quelle
2

JavaScript (ES6), 98 Byte

Übernimmt die Eingabe als zwei Ganzzahlen und ein Array von Zeichenfolgen. Gibt ein Array von Zeichenfolgen zurück.

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

Probieren Sie es online!

Kommentiert

( 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()
Arnauld
quelle
filter und map ?! Würde das Erstellen eines neuen Arrays mit reduceoder einer rekursiven Lösung nicht kürzer ausfallen? Am Telefon, in der Kneipe, oder ich probiere es selbst aus.
Shaggy
@Shaggy Es gibt wahrscheinlich einen kürzeren Weg, aber ich denke, dass diese Methode dazu verdammt ist, 2 Durchgänge zu verwenden: Die 2. Schleife kann nicht beginnen, bevor die 1. endet und beide Xund Ysind sicher bekannt.
Arnauld,
2

Java 10, 204 Bytes

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

Ändert das Eingabearray, anstatt ein neues zurückzugeben, um Bytes zu sparen. Dies bedeutet, dass entfernte Linien werden"" stattdessen . Wenn dies nicht erlaubt ist, werde ich es ändern.

Probieren Sie es online aus.

Erläuterung:

(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

Beispielsweise:

Mit den Eingängen start = "(", end = ")"undlines =

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

Die erste Schleife schneidet es oben und links ab und ändert es in:

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

Die zweite Schleife schneidet es unten und rechts zu und ändert es in:

["",
 "(but this text",
 "is in a box  )",
 ""]
Kevin Cruijssen
quelle
1

Retina 0.8.2 , 110 Bytes

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

Probieren Sie es online! Erläuterung:

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

Löschen Sie die Eingabezeilen vor der ersten Zeile des Feldes.

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

Befindet sich das Startzeichen in der linken Spalte der Eingabe, löschen Sie es.

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

Wenn das Startzeichen noch nicht gelöscht wurde, verschieben Sie alle Eingabespalten um eins nach links und wiederholen Sie den Vorgang von Anfang an.

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

Löschen Sie das Endzeichen und alles in der Eingabe nach dem Endzeichen.

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

Kürzen Sie alle Zeilen auf die Länge der nächsten Zeile. Dies funktioniert, indem alle bis auf ein Zeichen in jeder Zeile gezählt werden und dann versucht wird, bis zu dieser Anzahl von Zeichen in der nächsten Zeile übereinzustimmen. Gelingt dies, war die zweite Zeile kürzer, sodass das letzte Zeichen gelöscht und die Schleife wiederholt wird.

Neil
quelle
0

C (gcc) , 237 Bytes

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

Probieren Sie es online!

Ich bin mir zu 99% sicher, dass dies mit einer Art Hilfsfunktion verkürzt werden kann, um den horizontalen Index eines Zeichens und den Zeiger auf ein Zeichen zu finden, da er zweimal wiederholt wird. Leider konnte ich nicht kurz genug finden, um es zu tun, ich kann es später noch einmal versuchen, wenn ich die Zeit finde.

Beschreibung

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;
    }
}
LambdaBeta
quelle
1
Noch besser: 219 Bytes
Zacharý
0

Stax , 15 Bytes

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

Führen Sie es aus, und debuggen Sie es

In der ersten Eingabezeile werden die Box-Trennzeichen (1 oder 2) verwendet. Der Rest der Zeilen ist der Eingabe-Body.

Ausgepackt, ungolfed und kommentiert sieht es so aus.

            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

Führen Sie dieses aus

rekursiv
quelle