Pangkas Tantangan Seni ASCII

13

Seni ASCII itu menyenangkan. Editor teks modern sangat pandai memanipulasi teks. Apakah bahasa pemrograman modern sesuai dengan tugasnya?

Satu tugas umum dalam manipulasi seni ASCII adalah memotong teks menjadi persegi panjang di antara dua karakter. Ini adalah tugas yang harus Anda laksanakan dalam tantangan ini.

Detail

Program Anda akan mengambil 3 input:

  • yang pertama adalah karakter 'awal' dari blok - menandai sudut kiri atas
  • yang kedua adalah karakter 'ujung' dari blok - menandai sudut kanan bawah
  • yang ketiga adalah beberapa bentuk teks multiline, baik string, atau daftar string, atau nama file, atau apa pun

Hasilnya akan berupa teks multiline (sekali lagi, dalam salah satu format di atas) yang dipangkas menjadi persegi panjang di antara input yang diberikan. Perhatikan bahwa dua input pertama mungkin tidak unik.

Kasus tepi

Kotak harus selalu memiliki volume setidaknya 2. Dengan demikian:

()     (
       )

adalah kotak tetapi ini:

)(     )      (
       (     )

tidak (dengan mulai = (dan akhir = )).

Input hanya akan berisi satu kotak. Dengan demikian karakter awal dan akhir hanya boleh muncul sekali, kecuali mereka adalah karakter yang sama dalam hal ini mereka harus muncul tepat dua kali.

Selain itu setiap baris dalam input harus setidaknya sepanjang jarak dari awal garis ke tepi kanan kotak di input.

Program Anda tidak perlu menangani input yang tidak valid; mereka dapat mengakibatkan perilaku yang tidak terdefinisi.

Aturan

Aturan kode-golf berlaku. Kode terpendek menang.

Contohnya

Hari yang cerah: start: ( end: ) input:

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

Keluaran:

(but this text
is in a box  )

Perhatikan juga pengupasan ruang horizontal. Tanaman seni ASCII adalah 2d.

Hari hujan: start: ( end: ) input:

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

Keluaran:

(
)

Awal / akhir yang sama: start: / end: / input:

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

Keluaran:

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

Masukan tidak valid: start: ( end: ) input:

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

Input 2 tidak valid: start: ( end: ) input:

(The lines must already be square 
so this line that is too short
relative to this end, is illegal)
LambdaBeta
sumber
Bagaimana dengan kotak yang valid dengan garis di luar yang lebih pendek dari kotak?
seadoggie01
1
input diklarifikasi, juga tidak valid
LambdaBeta
apa yang harus menjadi hasil jika input tidak valid? atau mereka disebutkan sehingga mereka tidak harus diurus?
Uriel
1
Hasilnya seperti perilaku yang tidak terdefinisi dalam C, jangan khawatir tentang hal itu, apapun itu.
LambdaBeta
Ini adalah tantangan kecil yang tidak menyenangkan: pekerjaan bagus!
seadoggie01

Jawaban:

15

Vim, 16 , 12 byte / penekanan tombol

#<C-v>Nj*yggVGp

Cobalah online! dalam penerjemah V

Editor teks modern sangat pandai memanipulasi teks. Apakah bahasa pemrograman modern sesuai dengan tugasnya?

Saya yakin editor teks lama bahkan lebih baik! : D

Meskipun tidak harus, jawaban ini bekerja dengan kedua input "tidak valid" yang diberikan, menghasilkan

 rectangular (
) which is ill

dan

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

Penjelasan:

#               " 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
James
sumber
1
Kebetulan ini adalah persis penggunaan-kasus yang saya lakukan untuk meminta saya untuk menulis tantangan ini. Saya memiliki makro q saya /\/<cr><c-v>nygv$o0dpatau sesuatu seperti itu terlalu lama :)
LambdaBeta
2
Ya, persegi panjang adalah yang paling buruk !
AdmBorkBork
6

Jelly , 13 byte

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

Tautan diad yang menerima daftar karakter awal dan akhir di sebelah kiri dan daftar garis (sebagai daftar karakter) di sebelah kanan yang menghasilkan daftar garis (sebagai daftar karakter).

Cobalah online! (program lengkap - jika input Python valid, input Python-string-quote.)

Bagaimana?

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

Sebagai contoh, dengan kiri = ['a', 'b']dan kanan (sebagai daftar daftar karakter - garis):

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

=€menghasilkan daftar dua daftar daftar (yang berkinerja pertama 'a'=, yang kedua 'b'=):

00000000         00000000
00100000         00000000
00000000    ,    00000000
00000000         00000100
00000000         00000000

menjumlahkan ini menghasilkan satu daftar daftar (menjumlahkan elemen-bijaksana):

00000000
00100000
00000000
00000100
00000000

ŒṪkemudian memberi kita indeks multi-dimensi (1-diindeks) dari non-nol, [[2,3],[4,6]]- yaitu [[top,left],[bottom,right]].

r/kemudian melakukan [2,3]r[4,6]yang, karena rvektorisasi, seperti [2r4, 3r6], mengevaluasi ke [[2,3,4],[3,4,5,6]]- yaitu [rows,columns].

,þ/kemudian melakukan di [2,3,4],þ[3,4,5,6]mana þinstruksi luar-poduct dan ,berpasangan. Ini menghasilkan semua [row,column]nilai berdasarkan kolom, dalam hal ini:

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

Kami ingin ini dengan baris, jadi Zdigunakan untuk memindahkan ini ke:

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

Akhirnya œịindeks kembali ke jalur input:

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

Perlu dicatat bahwa ketika kedua karakter pembatas adalah sama =€mengidentifikasi dua kali tetapi SŒṪakhirnya melakukan hal yang benar, karena 2itu benar, misalnya dengan ['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
sumber
... Saya membaca penjelasannya, tetapi saya masih belum memahaminya. o_o Bisakah Anda menambahkan contoh yang berfungsi, mungkin?
DLosc
Insentif: Saya akan menerima jawaban Anda jika sudah dijelaskan sepenuhnya. :)
LambdaBeta
1
@Dosc - selesai, semoga membantu.
Jonathan Allan
@LambdaBeta - jawaban V lebih pendek.
Jonathan Allan
... err jawaban Vim bahkan.
Jonathan Allan
5

APL (Dyalog) , 38 30 byte

4 byte disimpan berkat @EriktheOutgolfer

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

Cobalah online!

Uriel
sumber
terlalu rumit. Anda bisa menerima matriks alih-alih vektor vektor, cari dua posisi dengan ⍸matrix∊separators, dan lakukan take / drop dengannya
ngn
(⍸a=⎕)↓(1+⍸a=⎕)↑a←⎕dengan⎕io←0
ngn
@ ngn OP mengatakan jumlah karakter berbeda di antara baris jadi saya berasumsi input harus vektor sebelum diproses. Meski begitu, saya memerlukan bagian seleksi (pertama dan memutar) jika pembatas menunjukkan beberapa kali (lihat kasus uji ketiga), tapi saya kira dropnya memotong beberapa byte, jadi terima kasih! Saya akan memperbarui setelah saya sampai di PC
Uriel
oops ... Saya lupa tentang kasus ketiga, maaf. Maka mungkin: ⊃{⌽⊖⍵↓⍨⊃⍸⍺=⍵}/⎕⎕⎕(sic, dengan 3 trailing quads) yang bahkan lebih pendek. Atau ... ⎕⎕(↑⎕)jika matriks pra-campuran tidak diizinkan.
ngn
3

Jelly , 14 byte

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

Cobalah online!

Erik the Outgolfer
sumber
Saya mencoba menjalankan kode Anda pada beberapa contoh lain, tetapi hanya mengalami kerusakan. Apakah itu bug, atau saya hanya melakukan sesuatu yang salah?
Ilmari Karonen
@IlmariKaronen Anda belum mengutip argumen kedua dengan benar (tidak menyebutkannya di pos); bungkus dengan tanda kutip tunggal atau ganda. Cara Anda memintanya, argumen kedua adalah tuple (Python) kosong ( ()), bukan '()'. Jika parse-mampu, perlu dikutip, namun, saya //tidak perlu dikutip (operator divisi integer tanpa operan? Hm ...).
Erik the Outgolfer
@IlmariKaronen Saya "berpikir" yang ()hanya ditafsirkan oleh Jelly sebagai semacam karakter khusus. Kebanyakan pasangan karakter saya coba bekerja. Saya ingin mendengar apa yang dipikirkan orang yang lebih akrab dengan Jelly. EDIT: ninja-red oleh erik the outgolfer
LambdaBeta
Oke, ya, itu berhasil.
Ilmari Karonen
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]

Cobalah online!

TFeld
sumber
2

Kanvas , 37 byte

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

Coba di sini!

36 byte untuk mendapatkan koordinat karakter (dan mengubahnya menjadi x, y, w, h karena itu yang diperlukan) dan 1 byte untuk mendapatkan subbagian .. Harus ada pendekatan yang lebih baik

dzaima
sumber
2

JavaScript (ES6), 98 byte

Mengambil input sebagai dua bilangan bulat dan larik string. Mengembalikan array string.

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

Cobalah online!

Berkomentar

( 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
sumber
filter dan map ? Apakah membangun array baru dengan reduceatau solusi rekursif tidak berhasil lebih pendek? Di telepon saya, di pub atau saya akan mencobanya sendiri.
Shaggy
@Shaggy Mungkin ada cara yang lebih pendek memang, tapi saya berpikir bahwa ini metode ditakdirkan untuk menggunakan 2 melewati: 2 lingkaran tidak dapat dimulai sebelum 1 satu Menghentikan dan kedua Xdan Ydikenal pasti.
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);}

Memodifikasi input-array alih-alih mengembalikan yang baru untuk menghemat byte. Namun, ini berarti bahwa garis yang dihapus menjadi ""sebaliknya. Jika ini tidak diizinkan, saya akan mengubahnya.

Cobalah online.

Penjelasan:

(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

Sebagai contoh:

Dengan input start = "(", end = ")"danlines =

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

loop pertama akan memotongnya di bagian atas dan kiri, mengubahnya menjadi ini:

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

loop kedua akan memotongnya di bagian bawah dan kanan, mengubahnya menjadi ini:

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

Retina 0.8.2 , 110 byte

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

Cobalah online! Penjelasan:

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

Hapus baris input sebelum baris pertama kotak.

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

Jika karakter awal ada di kolom kiri input, hapus saja.

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

Jika karakter awal belum dihapus, geser semua kolom input yang ditinggalkan oleh satu dan ulangi dari awal.

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

Hapus karakter akhir dan semua yang ada di input setelah karakter akhir.

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

Pangkas semua garis dengan panjang baris berikutnya. Ini berfungsi dengan menghitung semua kecuali satu karakter pada setiap baris, kemudian mencoba mencocokkan dengan banyak karakter pada baris berikutnya; jika ini berhasil maka baris kedua lebih pendek, sehingga karakter terakhir dihapus dan loop berulang.

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

Cobalah online!

Saya yakin 99% ini dapat disingkat menggunakan semacam fungsi pembantu untuk menemukan indeks horizontal dan pointer ke karakter, karena diulang dua kali. Sayangnya saya tidak dapat menemukan cara yang cukup singkat untuk melakukannya, saya dapat mencoba lagi nanti jika saya menemukan waktu.

Deskripsi

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
sumber
1
Bahkan lebih baik: 219 byte
Zacharý
0

Stax , 15 byte

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

Jalankan dan debug itu

Dibutuhkan set karakter pembatas kotak (1 atau 2) pada baris input pertama. Sisa baris adalah badan input.

Dibongkar, tidak diserang, dan dikomentari, sepertinya ini.

            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

Jalankan yang ini

rekursif
sumber