Ubah tabel seni ASCII menjadi tabel UTF-8

13

Ketika saya menulis dokumentasi, komentar, dll. Saya suka membuat tabel ASCII. Mereka biasanya terlihat cukup bagus, tetapi saya selalu merasa bahwa mereka dapat terlihat lebih baik - terutama karena UTF-8 / Unicode menyertakan karakter kotak gambar . Namun, karakter ini sangat memberatkan untuk digunakan, membutuhkan beberapa penekanan tombol untuk memasukkan. Tugas Anda? Tulis sebuah program atau fungsi yang dapat secara otomatis mengonversi tabel ASCII ke setara UTF-8 / Unicode.

Tantangan ini dikosongkan .

Tantangan

Tulis sebuah program, yang diberi tabel ASCII sebagai string input, mengeluarkan tabel yang digambar ulang dengan karakter menggambar kotak Unicode / UTF-8. Secara khusus, karakter yang merupakan bagian dari tabel harus diterjemahkan sebagai berikut:

(Unicode, 3 bytes each in UTF-8)
- to ─ (\u2500)
| to │ (\u2502)
= to ═ (\u2550)

and + to one of:
   ┌ (\u250C), ┐ (\u2510), └ (\u2514), ┘ (\u2518),
   ├ (\u251C), ┤ (\u2524), ┬ (\u252C), ┴ (\u2534),
   ┼ (\u253C)
or, if '=' on either side:
   ╒ (\u2552), ╕ (\u2555), ╘ (\u2558), ╛ (\u255D),
   ╞ (\u255E), ╡ (\u2561), ╤ (\u2564), ╧ (\u2567),
   ╪ (\u256A)

Detail

I / O:

  • I / O standar diizinkan
  • Anda dapat mengambil input dalam format wajar apa pun, termasuk tabel sebagai string, atau jalur ke file yang berisi tabel.
  • Anda dapat menampilkan ke file dan mengambil nama file sebagai argumen tambahan.
    • Namun, Anda tidak dapat mengubah file input . (Ini harus dipertahankan untuk kemudahan pengeditan di masa depan)

Memasukkan:

  • Anda dapat mengasumsikan bahwa setiap baris input telah diisi dengan panjang yang sama dengan .
  • Anda tidak boleh berasumsi bahwa karakter pertama setelah baris baru adalah bagian dari batas tabel (karena mungkin spasi).
  • Input dianggap sebagai tabel yang valid jika semua karakter (yang merupakan bagian dari tabel) -=|terhubung dengan tepat dua karakter dan +terhubung ke setidaknya satu karakter baik secara horizontal maupun vertikal.
  • Program Anda mungkin tidak menghasilkan kesalahan dengan input yang valid.
  • Jika input tidak valid perilaku tidak terdefinisi dan Anda dapat menghasilkan output apa pun.
  • Input dapat berisi karakter UTF-8, termasuk karakter gambar kotak.

Keluaran:

  • Setiap karakter -=|+yang bukan bagian dari tabel harus dibiarkan apa adanya.
  • Demikian pula, karakter lain apa pun harus dibiarkan apa adanya.
  • Sebuah baris baru yang memimpin dan / atau mengikuti diperbolehkan.

Lain:

  • Celah standar dilarang, seperti biasa.
  • Jika bahasa pilihan Anda memiliki built-in yang memecahkan masalah ini, Anda tidak dapat menggunakannya.
    • Ini berarti program, fungsi, subrutin atau instruksi yang akan menjadi pengiriman yang valid untuk tantangan ini tanpa tambahan.
  • Masing-masing karakter yang dibutuhkan dalam tantangan ini panjangnya tiga byte ketika dikodekan dalam UTF-8.

Karakter yang terhubung :

Karakter terhubung ke yang lain, jika:

  • Itu |dan langsung di atas atau di bawah +atau |;
  • Ini -dan langsung sebelum atau sesudah +atau -;
  • Ini =dan langsung sebelum atau sesudah +atau =;
  • Itu +dan langsung di atas atau di bawah |atau +, atau langsung sebelum atau sesudah -, =atau +.

Karakter dianggap sebagai bagian dari tabel, jika terhubung ke karakter apa pun yang merupakan bagian dari tabel. Menurut definisi, yang pertama +dalam input adalah bagian dari tabel.

Contohnya

Contoh tersedia di sini sebagai versi copy-pastable.

 Input:                    Output:
+------------------+      ┌──────────────────┐
|   Hello+World!   |      │   Hello+World!   │
+==================+      ╞══════════════════╡
| This is+my first |  ->  │ This is+my first │
|+-+ code|golf  +-+|      │+-+ code|golf  +-+│
|+-+chall|enge! +-+|      │+-+chall|enge! +-+│
+------------------+      └──────────────────┘

     +===+===+===+             ╒═══╤═══╤═══╕
     | 1 | 2 | 3 |             │ 1 │ 2 │ 3 │
 +---+===+===+===+         ┌───╪═══╪═══╪═══╡
 | 1 | 1 | 2 | 3 |         │ 1 │ 1 │ 2 │ 3 │
 +---+---+---+---+    ->   ├───┼───┼───┼───┤
 | 2 | 2 | 4 | 6 |         │ 2 │ 2 │ 4 │ 6 │
 +---+---+---+---+         ├───┼───┼───┼───┤
 |-3 |-3 |-6 |-9 |         │-3 │-3 │-6 │-9 │
 +===+---+---+---+         ╘═══╧───┴───┴───┘

      +-----+         ->      <Undefined>

      +-----+         ->      ┌─────┐
      +-----+                 └─────┘

+-----------------+
|  Hello, World!  |
| This is invalid |   ->      <Undefined>
|      input      |
 -----------------+

       ++++                      ┌┬┬┐
       ++++           ->         ├┼┼┤
       ++++                      └┴┴┘

       +--+
       ++++           ->      <Undefined>
       +--+

Akhirnya...

Ini adalah , sehingga jumlah byte terkecil yang menang. Selamat bermain golf!


sumber
Dalam contoh pertama, mengapa +-+kutipan berturut-turut tidak dianggap membentuk tabel yang terhubung?
rekursif
Jika fungsi 16-bit mungkin menggunakan byte tunggal untuk mewakili ╡, bagaimana dengan jumlah byte?
14m2
@recursive Jika Anda maksud Hello Worldtabel pertama , tabel bagian dalam tidak dianggap membentuk tabel karena teks di dalam tabel harus tetap tidak berubah, dan mereka tidak dianggap sebagai bagian dari batas tabel luar karena mereka tidak terhubung dengan benar.
Jika Anda memaksudkan +----+contoh pertama , itu karena arah sudut akan ambigu.
1
Oh, "tidak ada tabel di dalam tabel kecuali jika mereka terhubung untuk memperpanjang kemungkinan tabel terluar" membuat ini jauh lebih sulit.
Jonathan Allan

Jawaban:

2

Python 3, 392 281 byte

Golf sedikit lebih banyak dan dikonversi ke solusi rekursif alih-alih yang berulang:

def h(a):
 def g(i):
  k=-3;d=a[i]=='=';z[i]=''
  for p,j,r in zip((1,2,4,8),(i+1,i+w,i-1,i-w),('+-=','+|')*2):
   if 0<=j<len(a)and{a[i],a[j]}<={*r}:k+=p;d|=a[j]=='=';z[j]and g(j)
  z[i]="┌╒!!─═┐╕┬╤@@└╘││├╞┘╛┴╧┤╡┼╪"[2*k+d]
 w=a.find('\n')+1;z=[*a];g(a.find('+'))
 return''.join(z)

Mengambil string dengan panjang yang sama dengan baris yang dipisahkan oleh baris baru, dan mengembalikan string dalam format yang sama. Dapat melempar pengecualian pada input yang tidak valid.

Solusi sebelumnya:

def h(a):
 i=a.find('+');q=[i];w=a.find('\n')+1;z=[*a]
 while q:
  i=q.pop();c=a[i];k=-5
  for p,j in enumerate((i+1,i-1,i+w,i-w)):
   r='++-|='[p>1::2]
   if 0<=j<len(a)and a[i]in r and a[j]in r:
    k+=1<<p;q+=[j][:z[j]<'─']
  z[i]='│'if c>'='else'─═'[a[i]>'-']if c>'+'else"┌╒┐╕┬╤@@└╘┘╛┴╧##├╞┤╡┼╪$$"['='in a[abs(i-1):i+2]::2][k]
 return''.join(z)

Versi tidak disatukan:

def h(a):
    i = a.find('+')         # find index of first '+'. It is first node
    q = [i]                 # in the queue of indexes to convert to unicode
    w = a.find('\n')+1      # width of the table
    z = [*a]                # strings are immutable, so copy it to a list

    while q:                # while the queue isn't empty
        i=q.pop()           # get the next index to process
        c=a[i]              # and the associated character

        k=-5                # 'k' is the index into the unicode string, U.  The way they
                            # are encoded, the first unicode value is at index 5. 

                 # directions  E   W   S   N
        for p,j in enumerate((i+1,i-1,i+w,i-w)):  # j is the index of an adjacent cell

            # r='++-|='[p>1::2] is equivalent to:
            if p > 1:
                r = '+|'    # compatible symbols for vertical connections
            else:
                r = '+-='   # compatible symbols for horizontal connections

            # if adjacent cell index is valid and the characters are compatible
            if 0 <= j < len(a) and a[i] in r and a[j] in r:
                k += 1<<p                 # update the unicode symbol index

                # q += [j][:z[j]<'─'] is equivalent to:
                if z[j] < '-':            # if the adjacent cell hasn't been converted already
                    q.append(j)           #  append it's index to the queue

            if c > '=':
                z[i] = '│'                # replace a '|' with a '│'

            elif c > '+':
                z[i] = '─═'[a[i]>'-']     # replace a '-' or '=' with '─' or '═' respectively 

            else:                                      # it's a '+'
                U = "┌╒┐╕┬╤@@└╘┘╛┴╧##├╞┤╡┼╪$$"         # even indexes are single horizontal line, 
                                                       # double horizontal lines are at odd indexes

                z[i] = U['='in a[abs(i-1):i+2]::2][k]  # '='in a[abs(i-1):i+2] is true if there is an '=' to the left or right
                                                       # so this selects the odd chars from U
                                                       #  then [k] selects the correct char

 return''.join(z)
RootTwo
sumber
3

Python 3 , 914 898 827 823 594 587 569 540 469 byte

Sunting: strategi berubah secara signifikan, sekarang membuat bitfield tetangga (mirip dengan jawaban dead-possum). Saya telah meninggalkan versi sebelumnya di bawah ini.

H='─│═-|=└╘++++┌╒├╞++┘╛++┴╧┐╕┤╡┬╤┼╪'
def n(l):
 def j(r,c,t=0):O=(0,r-1,c),(1,r,c+1),(2,r+1,c),(3,r,c-1);v=f(r,c);b=t|any(f(Y,X)=='='for i,Y,X in O);l[r][c]={'+':H[b+2*sum((f(Y,X)in H)<<x for x,Y,X in O)],**dict(zip(H[3:6],H))}.get(v,v);[f(Y,X)!=';'and v in'+++-|='[i%2::2]and j(Y,X,v=='=')for i,Y,X in O]
 for i,I in enumerate(l):
  if'+'in I:f=lambda r,c:l[r][c]if len(l)>r>=0and 0<=c<len(l[r])else';';j(i,I.index('+'));break

Cobalah online!

Input dalam bentuk daftar daftar karakter, yang diubah di tempat. Berulang dari + pertama yang ditemukannya.

x=range
C='┌┐└┘','╒╕╘╛'
D='┬┤┴├','╤╡╧╞'
A='┼╪'
H,V,T='─│═'
J={'-':H,'|':V,'=':T}
K=C[1]+D[1]+A[1]+'='+T
E=('+|','+-=')*2
F=['+|'+V,'+-='+H+T]*2
O=(0,-1,0),(1,0,1),(2,1,0),(3,0,-1)
for i in x(4):
 for j in{0,1,2,3}-{i}:F[i+2&3]+=D[0][j]+D[1][j]
 h=C[0][i]+C[1][i];F[i&2]+=h;F[3-2*(i&1)]+=h
def n(l):
 for i,I in enumerate(l):
  if'+'in I:r=i;c=I.index('+');break
 else:return l
 def f(r,c):
  try:assert c>=0 and r>=0;return l[r][c]
  except:return'\0'
 def j(r,c):
  v=f(r,c)
  l[r][c]=J.get(v,v)
  if v=='+':
   X=[f(r+Y,c+X)for i,Y,X in O];B=any(x in K for x in X);X=[X[x]in F[x]for x in x(4)];L=sum(X)
   if L in(2,3,4):l[r][c]=D[B][X.index(False)]if L==3 else C[B][X[0]*2+X[3]]if L==2 else A[B]
  for i,Y,X in O:
   if v in E[i]and f(r+Y,c+X)in E[i]:j(r+Y,c+X)
 j(r,c);return l

Cobalah online!

Inilah hal terdekat yang saya miliki dengan versi yang tidak disolf:

def tr(s):
    t='┌┐└┘','╒╕╘╛'
    t2='┬┤┴├','╤╡╧╞'
    A = '┼','╪'
    H,V,T = '─│═'
    Th = ''.join(x[1]for x in (t,t2,A))+'='+T
    ps = ['+|'+V, '+-='+H+T, '+|'+V, '+-='+H+T]
    ps2 = ('+|', '+-=')*2
    for i in range(4):
        for j in {0,1,2,3}-{i}:
            ps[(i+2)%4] += t2[0][j]+t2[1][j]
        h=t[0][i] + t[1][i]
        ps[i & 2] += h
        ps[3 - 2 * (i & 1)] += h

    l = [list(x) for x in s.split('\n')]
    r = 0
    for i,I in enumerate(l):
        if'+'in I:
            r=i;c=I.index('+')
            break
    def g(r,c): return l[r][c]
    def G(r,c):
        if r >= 0 and r < len(l) and c >= 0 and c < len(l[r]):
            return g(r,c)
        return '\0'
    def process(r,c):
        v = g(r,c)
        if v == '-': l[r][c] = H
        elif v == '|': l[r][c] = V
        elif v == '=': l[r][c] = T
        elif v == '+':
            all=[G(r-1,c),G(r,c+1),G(r+1,c),G(r,c-1)]
            bold=any(x in Th for x in all)
            for i in range(4):all[i] = all[i] in ps[i]
            N,E,S,W=all
            tt=sum(all)
            if tt == 3:
                l[r][c]=t2[bold][all.index(False)]
            elif tt == 2:
                l[r][c]=t[bold][N*2+W]
            elif tt == 4:
                l[r][c]=A[bold]
            else: return
        for i,(dy,dx) in enumerate(((-1,0),(0,1),(1,0),(0,-1))):
            if v in ps2[i] and G(r+dy,c+dx) in ps2[i]:
                process(r+dy,c+dx)
    process(r,c)
    return l
pbfy0
sumber
Perbaikan kecil untuk menghemat 9 byte (hingga 814) bit.ly/2NOu7HF
mypetlion
Lebih sedikit untuk 9 byte (805 byte sekarang) bit.ly/2pYom0x
mypetlion
Turun ke 763: bit.ly/2OxErsJ
mypetlion
1

JavaScript, 311 307 byte

X=>(O=[...X],P=(I,j=0,_=0)=>!P[I]&&(P[I]=1,['-─1','|│','=═1'].map(([a,b,n=X.indexOf('\n')+1])=>[-n,+n].map(n=>{for(i=I;X[i+=n]==a;)O[i]=b
if(X[i]=='+')j|=[1,2,4,8,I-i>1&&17,i-I>1&&18][_],P(i)
_++})),O[I]='┘└┴ ┐┌┬ ┤├┼     ╛╘╧ ╕╒╤ ╡╞╪'[j-5]),P(X.indexOf`+`),O.join``)

Penjelasan

Mulai dari +persimpangan yang ditemukan pertama kali , program mencoba untuk menemukan jalur ke persimpangan lain di setiap arah, melakukan penggantian saat berjalan. Ini menyimpan arah yang ditemukan dan negara "berbatasan ganda" dalam bitmap, yang kemudian menentukan karakter persimpangan yang sesuai.

// Take an input string X
f = X => {
    // Copy the input string into an array so characters can be overwritten and eventually output
    O = [...X]

    // Define a function that processes a junction ("+" symbol) at index I in the input string X:
    P = I => {
        // Make a bitmap to keep track of the direction coming out of the junction and double borders
        // Bits from right to left: west, east, north, south, double border
        // E.g. a double-bordered south/east junction corresponds to the binary number 11010 ("╒")
        let j = 0

        // A counter
        let _ = 0

        // Ensure this junction hasn't already been processed
        if(!P[I]){
            P[I] = 1,

            // We'll walk away from the junction in each of the four directions, then west and east again to check for double borders
            // i.e. walk along `a`, replace with `b`, move index `i` by `n`
            // 1st pass: walk along "-", replace with "─", move index by 1
            // 2nd pass: walk along "|", replace with "│", move index by the width of the input (plus 1 for the newline) to traverse vertically
            // 3rd pass: walk along "=", replace with "═", move index by 1
            ['-─1','|│','=═1'].map(([a, b, n = X.indexOf('\n') + 1])=>
                // We'll walk in the negative and positive directions for each pass
                [-n,+n].map(n=>{
                    // Start the walk
                    i=I
                    // Keep walking (incrementing by n) as long as we're on a "path" character, "a"
                    while(i += n, X[i] == a)
                        // Replace the corresponding character in the output with "b"
                        O[i] = b

                    // Upon reaching another junction at index i:
                    if(X[i] == '+'){
                        // OR the bitmap according to the direction we walked
                        j |= [
                            // Pass 1: Horizontal
                            1, // west
                            2, // east

                            // Pass 2: Vertical
                            4, // north
                            8, // south

                            // Pass 3: Double Horizontal (only if we've walked more than 1 step)
                            I-i > 1 && 17, // west, double border
                            i-I > 1 && 18 // east, double border
                        ][_]

                        // Process the junction we walked to
                        P(i)
                    }
                    _++
                })
            )

            // Finally, replace the "+" with a proper junction character based on the bitmap value
            O[I] = '     ┘└┴ ┐┌┬ ┤├┼     ╛╘╧ ╕╒╤ ╡╞╪'[j]
        }
    }

    // Process the first junction to kick off the recursion
    P(X.indexOf`+`)

    // Return our modified character array as a joined string
    return O.join``
}
Darrylyeo
sumber
Memperbaiki - Saya pasti melihat jumlah karakter dan bukan jumlah byte.
darrylyeo
1

Python 3 , 599 byte

Saya tidak terlalu pandai bermain golf di Python 3, tapi (yang memalukan) saya tidak bisa mendapatkan hasil normal dari karakter UTF-8 di Python 2. Jadi, inilah kita.

Saya kira satu-satunya trik yang menarik di sini adalah menentukan +tranformasi.
Saya telah menyandikan semua varian yang mungkin dengan alamat 4-bit. Setiap bit alamat menyerupai koneksi ke sel tetangga. Jadi 0 - tidak ada koneksi dan 1 - koneksi.
1111adalah
0011yang
dll
Beberapa konfigurasi dari koneksi yang tidak valid dan diganti dengan nilai-nilai boneka:'012┐45┌┬8┘0┤└┴├┼'

Jika ada sel neightbour sel berisi =, daftar kedua akan digunakan dengan garis dua kali lipat.

['012┐45┌┬8┘0┤└┴├┼','012╕45╒╤8╛0╡╘╧╞╪']['='in r]

Alamat digabungkan di sini.

r=''.join([str(int(V(y,x)))+W(y,x)for y,x in[(Y-1,X),(Y,X+1),(Y+1,X),(Y,X-1)]])

rberisi string panjang 8, di mana setiap dua karakter adalah 1/0 dan sebenarnya neightbour char.
Sebagai contoh: 1+0y1-1|.
Ini digunakan untuk memilih daftar substitusi seperti yang ditunjukkan sebelumnya. Dan kemudian dikontrak untuk alamat:int(r[0::2],2)

Lambda ini digunakan untuk memverifikasi bahwa koordinat sel valid dan karakter sel adalah salah satu dari '+ - | ='

V=lambda y,x:~0<x<len(I[0])and~0<y<len(I)and I[y][x]in'+-|='

Lambda ini digunakan untuk menerima char dari sel. Mengembalikan ' 'jika koordinat tidak valid. (pasti bisa bermain golf)

W=lambda y,x:V(y,x)and I[y][x]or' '

Kondisi untuk rekursi. Mungkin golf juga.

if Z in'+-=':F(Y,X+1);F(Y,X-1)
if Z in'+|':F(Y-1,X);F(Y+1,X)

I=eval(input())
J=[i[:]for i in I]
V=lambda y,x:~0<x<len(I[0])and~0<y<len(I)and I[y][x]in'+-|='
W=lambda y,x:V(y,x)and I[y][x]or' '
def F(Y,X):
 if V(Y,X)and I[Y][X]==J[Y][X]:
  Z=I[Y][X]
  if','>Z:
   r=''.join([str(int(V(y,x)))+W(y,x)for y,x in[(Y-1,X),(Y,X+1),(Y+1,X),(Y,X-1)]])
   J[Y][X]=['012┐45┌┬8┘0┤└┴├┼','012╕45╒╤8╛0╡╘╧╞╪']['='in r][int(r[0::2],2)]
  else:J[Y][X]=dict(zip('|-=','│─═'))[Z]
  if Z in'+-=':F(Y,X+1);F(Y,X-1)
  if Z in'+|':F(Y-1,X);F(Y+1,X)
e=enumerate
F(*[(y,x)for y,r in e(I)for x,c in e(r)if'+'==c][0])
for r in J:print(''.join(r))

Cobalah online!

Possum Mati
sumber