Chuyển đổi bảng nghệ thuật ASCII thành bảng UTF-8


13

Khi tôi viết tài liệu, bình luận, v.v. Tôi thích làm bảng ASCII. Chúng thường trông khá đẹp, nhưng tôi luôn cảm thấy rằng chúng có thể trông thậm chí còn tốt hơn - đặc biệt là vì UTF-8 / Unicode bao gồm các ký tự vẽ hộp . Tuy nhiên, các ký tự này rất nặng nề để sử dụng, đòi hỏi một số lần nhấn phím để chèn. Nhiệm vụ của bạn? Viết chương trình hoặc hàm có thể tự động chuyển đổi các bảng ASCII thành tương đương UTF-8 / Unicode.

Thử thách này đã được sandbox .

Thử thách

Viết chương trình, đưa ra bảng ASCII dưới dạng chuỗi đầu vào, xuất ra bảng vẽ lại với các ký tự vẽ hộp Unicode / UTF-8. Cụ thể, các ký tự là một phần của bảng nên được dịch như sau:

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

Chi tiết

Tôi / O:

  • I / O mặc định được cho phép
  • Bạn có thể lấy đầu vào ở bất kỳ định dạng hợp lý nào, bao gồm bảng dưới dạng chuỗi hoặc đường dẫn đến tệp chứa bảng.
  • Bạn có thể xuất ra một tệp và lấy tên tệp làm đối số bổ sung.
    • Tuy nhiên, bạn không thể sửa đổi tệp đầu vào . (Nó nên được giữ lại để dễ chỉnh sửa trong tương lai)

Đầu vào:

  • Bạn có thể giả sử rằng mọi hàng đầu vào đã được đệm có cùng độ dài với .
  • Bạn không được cho rằng ký tự đầu tiên sau dòng mới là một phần của đường viền bảng (vì nó có thể là khoảng trắng).
  • Đầu vào được coi là một bảng hợp lệ nếu tất cả các ký tự (là một phần của bảng) -=|được kết nối với chính xác hai ký tự và +được kết nối với ít nhất một ký tự theo cả chiều ngang và chiều dọc.
  • Chương trình của bạn có thể không tạo ra bất kỳ lỗi nào với đầu vào hợp lệ.
  • Nếu đầu vào không hợp lệ, hành vi không được xác định và bạn có thể tạo ra bất kỳ đầu ra nào.
  • Đầu vào có thể chứa bất kỳ ký tự UTF-8 nào, bao gồm các ký tự vẽ hộp.

Đầu ra:

  • Bất kỳ ký tự -=|+nào không phải là một phần của bảng phải được giữ nguyên.
  • Tương tự, bất kỳ ký tự nào khác phải được giữ nguyên.
  • Một dòng mới hàng đầu và / hoặc trailing được cho phép.

Khác:

  • Lỗ hổng tiêu chuẩn bị cấm, như thường lệ.
  • Nếu ngôn ngữ ưa thích của bạn có tích hợp sẵn để giải quyết vấn đề này, bạn không thể sử dụng ngôn ngữ đó.
    • Điều này có nghĩa là các chương trình, chức năng, chương trình con hoặc hướng dẫn sẽ được đệ trình hợp lệ cho thử thách này mà không cần bổ sung.
  • Mỗi ký tự cần thiết trong thử thách này dài ba byte khi chúng được mã hóa bằng UTF-8.

Các nhân vật được kết nối :

Một ký tự được kết nối với một ký tự khác, nếu:

  • Nó là |và trực tiếp trên hoặc dưới +hoặc |;
  • Nó là -và trực tiếp trước hoặc sau +hoặc -;
  • Nó là =và trực tiếp trước hoặc sau +hoặc =;
  • Nó là +và trực tiếp trên hoặc dưới |hoặc +, hoặc trực tiếp trước hoặc sau -, =hoặc +.

Một ký tự được coi là một phần của bảng, nếu nó được kết nối với bất kỳ ký tự nào là một phần của bảng. Theo định nghĩa, đầu tiên +trong đầu vào là một phần của bảng.

Ví dụ

Các ví dụ có sẵn ở đây dưới dạng phiên bản có thể sao chép.

 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>
       +--+

Cuối cùng ...

Đây là , nên số byte ít nhất sẽ thắng. Chúc bạn chơi golf vui vẻ!


Trong ví dụ đầu tiên, tại sao các +-+đoạn trích liên tiếp không được xem xét để tạo thành một bảng được kết nối?
đệ quy

Nếu một hàm có thể 16 bit sử dụng một byte đơn để biểu thị, thì số byte đó như thế nào?
l4m2

@recursive Nếu bạn có nghĩa là Hello Worldbảng đầu tiên , các bảng bên trong không được coi là tạo thành một bảng vì văn bản bên trong bảng phải không thay đổi và chúng không được coi là một phần của đường viền bảng bên ngoài vì chúng không được kết nối với chúng đúng cách.

Nếu bạn có nghĩa là +----+ví dụ đầu tiên , đó sẽ là vì hướng của các góc sẽ mơ hồ.

1
Ồ, yêu cầu "không có bảng trong bảng trừ khi chúng kết nối để mở rộng bảng ngoài cùng có thể" làm cho điều này khó khăn hơn nhiều.
Jonathan Allan

Câu trả lời:


2

Python 3, 392 281 byte

Đánh gôn thêm một chút nữa và chuyển thành giải pháp đệ quy thay vì lặp lại:

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)

Lấy một chuỗi các hàng có độ dài bằng nhau được phân tách bằng các dòng mới và trả về một chuỗi có cùng định dạng. Có thể ném một ngoại lệ vào đầu vào không hợp lệ.

Giải pháp trước đây:

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)

Phiên bản bị đánh cắp:

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)

3

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

Chỉnh sửa: chiến lược đã thay đổi đáng kể, hiện đang tạo ra một chút hàng xóm (tương tự như câu trả lời của người chết). Tôi đã rời phiên bản trước đó bên dưới.

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

Hãy thử trực tuyến!

Đầu vào ở dạng danh sách các danh sách các ký tự, được sửa đổi tại chỗ. Thu hồi từ + đầu tiên mà nó tìm thấy.

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

Hãy thử trực tuyến!

Đây là điều gần nhất tôi có với một phiên bản không có ý thức:

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

Cải tiến nhỏ để tiết kiệm 9 byte (xuống 814) bit.ly/2NOu7HF
mypetlion

Thêm vài thêm 9 byte (805 tại byte) bit.ly/2pYom0x
mypetlion

Xuống 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``)

Giải trình

Bắt đầu từ +ngã ba tìm thấy đầu tiên , chương trình cố gắng tìm đường dẫn đến các nút giao khác theo mọi hướng, thực hiện thay thế khi nó đi. Nó lưu trữ các hướng tìm thấy và trạng thái "viền kép" trong một bitmap, sau đó xác định ký tự đường nối thích hợp.

// 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``
}

Đã sửa lỗi - Tôi phải xem số lượng ký tự chứ không phải số byte.
darrylyeo

1

Python 3 , 599 byte

Tôi không giỏi chơi gôn trong Python 3, nhưng (thật xấu hổ) Tôi không thể có được đầu ra bình thường của các ký tự UTF-8 trong Python 2. Vì vậy, chúng ta ở đây.

Tôi đoán thủ thuật thú vị duy nhất ở đây là quyết định sự +yên tĩnh.
Tôi đã mã hóa tất cả các biến thể có thể bằng địa chỉ 4 bit. Mỗi bit của địa chỉ giống như kết nối với tế bào neightbour. Vì vậy, 0 - không có kết nối và 1 - kết nối.
1111
0011
vv
Một số cấu hình các kết nối không hợp lệ và thay thế bằng các giá trị giả:'012┐45┌┬8┘0┤└┴├┼'

Nếu bất kỳ ô neightbour nào chứa =, danh sách thứ hai sẽ được sử dụng với các dòng nhân đôi.

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

Địa chỉ được kết hợp ở đây.

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

rchứa chuỗi 8 chiều dài, trong đó cứ hai ký tự là 1/0 và thực tế neightbour char.
Ví dụ : 1+0y1-1|.
Điều này được sử dụng để chọn danh sách thay thế như được hiển thị trước đó. Và sau đó ký hợp đồng với địa chỉ:int(r[0::2],2)

Lambda này được sử dụng để xác minh rằng tọa độ ô là hợp lệ và char của ô là một trong '+ - | ='

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

Lambda này được sử dụng để nhận char từ tế bào. Trả về ' 'nếu tọa độ không hợp lệ. (chắc chắn có thể được đánh gôn đi)

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

Điều kiện để đệ quy. Có thể chơi golf quá.

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

Hãy thử trực tuyến!

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.