### iron_bird_005

import re
import unicodedata

nn = ''

def 차원값(a1):
    return (type(a1) == list) + (type(a1[0]) == list if isinstance(a1, list) and a1 else 0)

def tt(aa1):
    
    dd1 = 차원값(aa1)
    if dd1 == 0: return aa1
    if dd1 == 1: aa1 = [aa1]
    
    길이 = max(len(row) for row in aa1)
    임시1 = [row2 + [nn]*(길이-len(row2)) for row2 in aa1]
    임시1 = [list(row) for row in zip(*임시1)]
    if len(임시1) == 1: 임시1 = 임시1[0]
    return 임시1

def 실제너비(aa1):
    ###한글 등 전각 문자는 2칸, 영문/숫자는 1칸으로 계산
    cc1 = 0 ## 너비
    for i in str(aa1):
        if unicodedata.east_asian_width(i) in ['W', 'F']:
            cc1 += 2
        else:
            cc1 += 1
    return cc1

def 텍스트_맞춤(aa1, aa2): ### (텍스트, lenth)
    ##주어진 길이에 맞춰 실제 너비만큼 공백을 채움 (좌측 정렬)
    cc1 = str(aa1)
    bb1 = aa2 - 실제너비(cc1) ## 필요한 공백
    
    if bb1 > 0:
        return cc1 + (" " * bb1)
    return cc1


def 프린트(aa1, aa2=None):

    aa2 = aa2 if aa2 is not None else 4

    print()
    try:
        dd1 = 차원값(aa1)
        
        if dd1 != 2 :
            print(aa1)
        else:
            for row in aa1:
                aa11 = [텍스트_맞춤(str(i), aa2) for i in row]
                print(" ".join(aa11))  
    except Exception:
        print(10**22)


def 행길이(aa1):
    return max(len(row) for row in aa1)

def 열길이(aa1):
    return len(aa1)


def 알맹이(aa1):

    괄호속 = re.search(r"\((.*)\)", aa1)
    내용 = 괄호속.group(1) if 괄호속 else aa1.strip()
    if 내용.startswith('[') and 내용.endswith(']'):
        return 리스트판별(내용)
    return 내용
    

def 타입판별0(aa1):

    aa1 = aa1.strip()

    if not aa1: return aa1

    if len(aa1) >= 2:
        bb1 = aa1[0] + aa1[-1]
        
        if bb1 == '""' : return aa1[1:][:-1]
        if bb1 == "''" : return aa1[1:][:-1]

    if (aa1 == "True") + (aa1 == "False") == 1:
        aa1 = aa1 == "True"

    else:
        try:
            aa1 = float(aa1)
            if aa1 % 1 == 0:
                aa1 = int(aa1)
                
        except ValueError:
            pass
    return aa1



def 리스트판별(aa1):
 
    aa11 = aa1[1:].strip().split(',')
    bb11 = [0] + [i.count('[') - i.count(']') for i in aa11] + [0]

    for i in range(len(bb11)):
        bb11[i] += bb11[i-1]
    bb11 = bb11[:-2]


    bb22 = [i.count('[') for i in aa11]


    bb33 = aa1.replace('[','').replace(']','').strip().split(',')
    bb33 = [타입판별0(i) for i in bb33]


    cc1 = []

    for i,j,k in zip(bb11,bb22,bb33):

        cc11 = cc1
        
        for _ in range(j):
            k = [k]
    
        for _ in range(i):
            cc11 = cc11[-1]

        cc11.append(k)
    
    return cc1




def 엑셀자료를_리스트로(aa1):

    aa11 = aa1.strip()[1:][:-1].split(';')
    aa11 = [i.strip().split(',') for i in aa11]
    aa11 = [[타입판별0(j) for j in i] for i in aa11]

    if len(aa11) == 1:
        return aa11[0]

    return aa11



def 타입판별(aa1):

    aa1 = aa1.strip()

    if not aa1: return aa1

    if len(aa1) >= 2:
        bb1 = aa1[0] + aa1[-1]

        if bb1 == '""' : return aa1[1:][:-1]
        if bb1 == "''" : return aa1[1:][:-1]
        if bb1 == '[]' : return 리스트판별(aa1)
        if bb1 == '{}' : return 엑셀자료를_리스트로(aa1)

    return 타입판별0(aa1)


def 스탭만들기(aa1):

    
    aa1 = aa1.replace('(',')').split(')')
    for i in range(len(aa1)):
        if i%2 == 1 :
            aa1[i] = aa1[i].replace('-','@빼기_기호@')
            aa1[i] = '(' + aa1[i] + ')'
    aa1 = "".join(aa1)

    aa1 = aa1.replace('+','+더하기+').replace('*','+곱하기+').replace('-','+빼기+')
    return aa1.split('+')


def 변환1(aa1):

    aa1 = aa1.replace('@빼기_기호@','-')
    if 'col' in aa1: return col(알맹이(aa1))
    if 'row' in aa1: return row(알맹이(aa1))
    if 'tt' in aa1: return tt(알맹이(aa1))
    return 타입판별(aa1)


def 아이언(aa1):

    if type(aa1) != str: 
            return aa1

    aa11 = 스탭만들기(aa1)

    aa11 = [변환1(i) for i in aa11]

    for i in range(len(aa11)):
        if aa11[i] == "곱하기" :
            aa11[i+1] = 곱하기(aa11[i-1],aa11[i+1])
            aa11[i-1] = aa11[i] = ''
    aa11 = [i for i in aa11 if i != '']

    for i in range(len(aa11)):

        if aa11[i] == "더하기" :
            aa11[i+1] = 더하기(aa11[i-1],aa11[i+1])
            aa11[i-1] = aa11[i] = ''

        elif aa11[i] == "빼기" :
            aa11[i+1] = 빼기(aa11[i-1],aa11[i+1])
            aa11[i-1] = aa11[i] = ''


    aa11 = [i for i in aa11 if i != '']
    

    return aa11[0]



def 아이언버드(aa1=None):

    import csv

    if type(aa1) == str and aa1[-4:] == '.csv':

        with open(aa1, 'r', encoding='utf-8-sig') as f:
                reader22 = list(csv.reader(f))

                행길이22 = 행길이(reader22)
                열길이22 = 열길이(reader22)

                reader33 = [['' for i in range(행길이22)] for j in range(열길이22)]

                for i in range(열길이22):
                    for j in range(len(reader22[i])):
                        reader33[i][j] = 타입판별(reader22[i][j])


        return 버드(reader33)

    elif type(aa1) == str and aa1:
        return 버드(아이언(aa1))

    else:
        return 버드(aa1)




         
def col(aa1):
    if isinstance(aa1, int): 
        return list(range(1, aa1 + 1))

    elif isinstance(aa1, str) :
        try:
            if ':' in aa1:
                시작, 끝 = map(int, aa1.split(':'))
                return list(range(시작, 끝 + 1))
            else:
                aa1 = int(aa1)
                return list(range(1, aa1 + 1))
        except (ValueError, TypeError):  
            return 10**22
    else:
        return 10**22

    

def row(aa1):
    return tt(col(aa1))



def 브로드캐스팅(aa1, aa2):
    
    dd1, dd2 = 차원값(aa1), 차원값(aa2)
    
    col1, col2 = 0, 0
    if dd1 == 2 and 차원값(tt(aa1)) == 1: col1 = 1
    if dd2 == 2 and 차원값(tt(aa2)) == 1: col2 = 1

    
    if col1 == dd2 == 1:
        aa11 = [a1*len(aa2) for a1 in aa1]
        aa22 = [aa2 for _ in aa1]
        aa1, aa2 = aa11, aa22
        return aa1, aa2

    elif dd1 == col2 == 1:
        aa11 = [aa1 for _ in aa2]
        aa22 = [a2*len(aa1) for a2 in aa2]
        aa1, aa2 = aa11, aa22
        return aa1, aa2

    if col1 == 1 and dd2 == 2:
    
        aa1 = aa1 + [[''] for i in range(len(aa2)-len(aa1))]
        aa1 = [a1*len(a2) for a1,a2 in zip(aa1,aa2)]
        return aa1, aa2
    
    elif dd1 == 2 and col2 == 1:
    
        aa2 = aa2 + [[''] for i in range(len(aa1)-len(aa2))]
        aa2 = [a1*len(a2) for a1,a2 in zip(aa2,aa1)]
        return aa1, aa2

    

    if dd1 == dd2 == 0:
        return aa1, aa2

    if dd1 == 0 and dd2 == 1:
        aa1 = [aa1 for _ in aa2]
        return aa1, aa2
    elif dd1 == 1 and dd2 == 0:
        aa2 = [aa2 for _ in aa1]
        return aa1, aa2
    
    if dd1 == dd2 == 1:
        bb1 = len(aa2) - len(aa1)
        aa1.extend([nn for i in range(bb1)])
        aa2.extend([nn for i in range(-bb1)])
        return aa1, aa2


    if dd1 == 0 and dd2 == 2 :
        aa1 = [[aa1]*len(i) for i in aa2]
        return aa1, aa2

    elif dd1 == 2 and dd2 == 0 :
        aa2 = [[aa2]*len(i) for i in aa1]
        return aa1, aa2


    if dd1 == 1 and dd2 == 2 :
        
        aa1 = [(aa1 + [nn for _ in range(len(i)-len(aa1))])[:len(i)] for i in aa2]
        return aa1, aa2
            
    elif dd1 == 2 and dd2 == 1 :

        aa2 = [(aa2 + [nn for _ in range(len(i)-len(aa2))])[:len(i)] for i in aa1]
        return aa1, aa2


    if dd1 == 2 and dd2 == 2 :
    
        aa1 = aa1 + [[''] for i in range(len(aa2)-len(aa1))]
        aa2 = aa2 + [[''] for i in range(len(aa1)-len(aa2))]
    
        aa1 = [i + ['' for _ in range(len(j) - len(i))] for i, j in zip(aa1, aa2)]
        aa2 = [i + ['' for _ in range(len(j) - len(i))] for i, j in zip(aa2, aa1)]


        return aa1, aa2
    
    return aa1, aa2


def 더하기_연산(aa1, aa2):

    
    if type(aa1) == list or type(aa2) == list:
            return 더하기(aa1, aa2)


    try:
        if aa1 == '':
            cc1 = aa2
        elif aa2 == '':
            cc1 = aa1
        

        else:
            try:
                cc1 = aa1 + aa2
            except TypeError:
                cc1 = str(aa1) + str(aa2)
    except TypeError:
        cc1 = ''
    
    return cc1



def 더하기(aa1, aa2):

        aa11, aa22 = 브로드캐스팅(aa1, aa2)

        dd11 = 차원값(aa11)

        if dd11 == 0:
            return 더하기_연산(aa11,aa22)
            

        elif dd11 == 1:
            return [더하기_연산(i11,i22) for i11, i22 in zip(aa11,aa22)]
            
        elif dd11 == 2:
            return [[더하기_연산(j11, j22) for j11, j22 in zip(i11, i22)] for i11, i22 in zip(aa11, aa22)]
        else: return 10*22



def 자릿수(값):
    if isinstance(값, float):
        return len(str(값).split('.')[1]) 
    return 0


def 곱하기_연산(aa1,aa2):


    
    if type(aa1) == list or type(aa2) == list:
            return 곱하기(aa1, aa2)


    if aa1 == '' or aa2 == '' or type(aa1) == type(aa2) == str :
            return ''
    

    if type(aa1) == type(aa2) == int :
        return aa1*aa2
    

    if isinstance(aa1, (int, float)) and isinstance(aa2, (int, float)):
        cc1 = round(aa1 * aa2, 자릿수(aa1) + 자릿수(aa2))
        if cc1 % 1 == 0:
            cc1 = int(cc1)
        return cc1
        
    if isinstance(aa1, (list, str)) and isinstance(aa2, (int, float)):

        aa22 = int(max(min(aa2,1),-1)*len(aa1))
        if aa22 > 0 : return aa1[:aa22]
        elif aa22 < 0 : return aa1[aa22:]
        else : return ''

    if isinstance(aa2, (list, str)) and isinstance(aa1, (int, float)):

        aa1 , aa2 = aa2 , aa1

        aa22 = int(max(min(aa2,1),-1)*len(aa1))
        if aa22 > 0 : return aa1[:aa22]
        elif aa22 < 0 : return aa1[aa22:]
        return ''
    
    return ''




def 곱하기(aa1, aa2):
        

        aa11, aa22 = 브로드캐스팅(aa1, aa2)

        dd11 = 차원값(aa11)

        if dd11 == 0:
            return 곱하기_연산(aa11,aa22)
            

        elif dd11 == 1:
            return [곱하기_연산(i11,i22) for i11, i22 in zip(aa11,aa22)]
            
        elif dd11 == 2:
            return [[곱하기_연산(j11, j22) for j11, j22 in zip(i11, i22)] for i11, i22 in zip(aa11, aa22)]
        else: return 10**22


def 빼기_연산(aa1, aa2):


    if type(aa1) == list or type(aa2) == list:
            return 빼기(aa1, aa2)

    try:
        if aa2 == '':
            return aa1
        elif aa1 == '':
            try: return -aa2
            except TypeError: return ''


        elif type(aa1) == str or type(aa2) == str:
            if str(aa2) not in str(aa1):
                return aa1
            return str(aa1).replace(str(aa2), "", 1).strip()


        else:
            return aa1 - aa2

    except TypeError:
        return ''


def 빼기(aa1, aa2): 

        aa11, aa22 = 브로드캐스팅(aa1, aa2)

        dd11 = 차원값(aa11)

        if dd11 == 0:
            return 빼기_연산(aa11,aa22)
            

        elif dd11 == 1:
            return [빼기_연산(i11,i22) for i11, i22 in zip(aa11,aa22)]
            
        elif dd11 == 2:
            return [[빼기_연산(j11, j22) for j11, j22 in zip(i11, i22)] for i11, i22 in zip(aa11, aa22)]
        else: return 10*22


def 타입(aa1):

    return [[type(j).__name__ for j in i] for i in aa1]



def 타입변환0(aa1):

    aa1 = str(aa1)
    aa1 = aa1.strip()

    if not aa1: return aa1

    if len(aa1) >= 2:
        bb1 = aa1[0] + aa1[-1]

        if bb1 == '""' : aa1 = aa1[1:][:-1]
        if bb1 == "''" : aa1 = aa1[1:][:-1]
        if bb1 == '[]' : return 리스트판별(aa1)
        if bb1 == '{}' : return 엑셀자료를_리스트로(aa1)

    return 타입판별0(aa1)


def 타입변환(aa1):

    
    if 차원값(aa1) == 0 : return 타입변환0(aa1)
    if 차원값(aa1) == 1 : return [타입변환0(i) for i in aa1]
    return [[타입변환0(j) for j in i] for i in aa1]



#######---------------------------------------------------------------------




class 버드:

    def __init__(self, a1):

        self.bb = a1


    def 아이언(self, aa2=None):
            if aa2 == None: return self
            if type(aa2) !=str : return 버드(aa2)
            self.bb = 아이언(aa2.replace('[]', str(self.bb)))
            return self


    def tt(self):
        aa1 = self.bb
        dd1 = 차원값(aa1)
        if dd1 == 0: return aa1
        if dd1 == 1: aa1 = [aa1]
        
        길이 = max(len(row) for row in aa1)
        임시1 = [row2 + [nn]*(길이-len(row2)) for row2 in aa1]
        임시1 = [list(row) for row in zip(*임시1)]
        if len(임시1) == 1: 임시1 = 임시1[0]
        self.bb = 임시1
        return self



    def 행복사(self, n=None):
            
            if not n : return self
            
            n = int(n)
            if 차원값(self.bb) == 0 : self.bb = [[self.bb]]
            elif 차원값(self.bb) == 1 : self.bb = [self.bb]


            self.bb = [row[:] for _ in range(n) for row in self.bb]

            return self 


   

    def 열복사(self, n=None):

        if not n : return self

        if 차원값(self.bb) == 0 : self.bb = [[self.bb]]
        elif 차원값(self.bb) == 1 : self.bb = [self.bb]

        self.tt().행복사(n).tt()
        return self



    def 프린트(self, aa2=None):

        aa1 = self.bb
        aa2 = aa2 if aa2 is not None else 4

        print()
        try:
            dd1 = 차원값(aa1)
            
            if dd1 != 2 :
                print(aa1)
                return self
            else:
                for row in aa1:
                    aa11 = [텍스트_맞춤(str(i), aa2) for i in row]
                    print(" ".join(aa11))
                return self
                
        except Exception:
            print(10**22)
            return self




    def 행(self, *aa2):

            if not aa2:
                return self
            
            aa1 = self.bb
            
            if 차원값(aa1) == 0 : aa1 = [[aa1]]
            elif 차원값(aa1) == 1 : aa1 = [aa1]



            if type(aa2[0]) == str and ':' in aa2[0]:

                bb1 = aa2[0].split(':')
                aa00 = int(bb1[0] == '0' or bb1[0] or 1)-1
                aa11 = int((bb1[1] == '0')*len(aa1) or bb1[1] or len(aa1))
                aa00 = aa00 + (len(aa1) + 1)*(aa00 < 0)
                aa11 = aa11 + (len(aa1) + 1)*(aa11 < 0)

                self.bb = aa1[aa00:aa11]
                return self

            elif type(aa2[0]) == str and ',' in aa2[0] :
                타겟 = [int(i) for i in aa2[0].split(',')]
            else:
                타겟 = [int(i) for i in aa2]

            타겟2 = [i - 1 if i > 0 else i for i in 타겟 if i != 0]
            self.bb = [aa1[i] for i in 타겟2]
            return self


    def 열(self, *aa2):

            return self.tt().행(*aa2).tt()

    

    def 더하기(self, aa2):

            bb2 = 버드(aa2).bb
            aa11, aa22 = 브로드캐스팅(self.bb, bb2)

            dd11 = 차원값(aa11)

            if dd11 == 0:
                self.bb = 더하기_연산(aa11,aa22)
                return self
                

            elif dd11 == 1:
                self.bb = [더하기_연산(i11,i22) for i11, i22 in zip(aa11,aa22)]
                return self
            
            elif dd11 == 2:
                self.bb = [[더하기_연산(j11, j22) for j11, j22 in zip(i11, i22)] for i11, i22 in zip(aa11, aa22)]
                return self

            else:
                self.bb = 10**22
                return self
            
    def 곱하기(self, aa2):

            bb2 = 버드(aa2).bb
            aa11, aa22 = 브로드캐스팅(self.bb, bb2)

            dd11 = 차원값(aa11)

            if dd11 == 0:
                self.bb = 곱하기_연산(aa11,aa22)
                return self
                

            elif dd11 == 1:
                self.bb = [곱하기_연산(i11,i22) for i11, i22 in zip(aa11,aa22)]
                return self
            
            elif dd11 == 2:
                self.bb = [[곱하기_연산(j11, j22) for j11, j22 in zip(i11, i22)] for i11, i22 in zip(aa11, aa22)]
                return self

            else:
                self.bb = 10*22
                return self


    def 빼기(self, aa2):

            bb2 = 버드(aa2).bb
            aa11, aa22 = 브로드캐스팅(self.bb, bb2)

            dd11 = 차원값(aa11)

            if dd11 == 0:
                self.bb = 빼기_연산(aa11,aa22)
                return self
                

            elif dd11 == 1:
                self.bb = [빼기_연산(i11,i22) for i11, i22 in zip(aa11,aa22)]
                return self
            
            elif dd11 == 2:
                self.bb = [[빼기_연산(j11, j22) for j11, j22 in zip(i11, i22)] for i11, i22 in zip(aa11, aa22)]
                return self

            else:
                self.bb = 10*22
                return self




    def 세이브(self, aa2):
        import csv
        aa1 = self.bb

        if type(aa2) != str or not aa2: return 버드(10**22)

        if type(aa1) != list:
            aa1 = [[aa1]]
        
        if aa1 and type(aa1[0]) != list:
            aa1 = [[i] for i in aa1]   

    
        try:
            with open(aa2, 'w', newline='', encoding='utf-8-sig') as f:
                csv.writer(f).writerows(aa1)
            print()
            print(f'-----저장 "{aa2}"-----')
            print()

            self.bb = aa1
            return self
        
        except Exception:
            return 버드(10**22)
    

    def save(self, aa2):
        return self.세이브(aa2)

    def print(self, aa2=None):
        return self.프린트(aa2)
    
    
    def pp(self, aa2=None):
        return self.프린트(aa2)
    
    def 변수화(self):
        return self.bb

    def 타입(self):

        dd1 = 차원값(self.bb)

        if dd1 == 2 : self.bb = [[type(j).__name__ for j in i] for i in self.bb]
        elif dd1 == 1 : self.bb = [type(i).__name__ for i in self.bb ]
        else : self.bb = type(self.bb).__name__

        return self

    def type(self):
        return self.타입()
    

    def 타입변환(self):

        aa1 = self.bb
        if 차원값(aa1) == 0 : self.bb = 타입변환0(aa1)
        elif 차원값(aa1) == 1 : self.bb = [타입변환0(i) for i in aa1]
        else : self.bb = [[타입변환0(j) for j in i] for i in aa1]
        return self


    def 반올림(self):

        dd1 = 차원값(self.bb)
        
        if dd1 == 2 : 
            self.bb = [[round(j) if type(j) in (float, int) else j for j in i] for i in self.bb]
        elif dd1 == 1 : 
            self.bb = [round(i) if type(i) in (float, int) else i for i in self.bb ]
        else : 
            self.bb = round(self.bb) if type(self.bb) in (float, int) else self.bb

        return self



