diff --git a/charconv-0.1.pyw b/charconv-0.1.pyw new file mode 100644 index 0000000..132ec15 --- /dev/null +++ b/charconv-0.1.pyw @@ -0,0 +1,466 @@ +#!/usr/bin/env python2 +# -*- coding: utf-8 -*- + +'''This is a small app that converts a character into various representations: +binary, hexademical code points, utf-8/utf-16 code points, decimal''' + +import codecs +import re +import sys +import ttk +import unicodedata + +from Tkinter import IntVar, Text, Tk, END + + +class Charconv(ttk.Frame): + def __init__(self, master): + '''Instantiating main Frame''' + ttk.Frame.__init__(self, master) + self.grid(sticky="nsew") + self.columnconfigure(0, weight=1) + self.columnconfigure(1, weight=1) + self.rowconfigure(0, weight=1) + self.rowconfigure(1, weight=1) + self.rowconfigure(2, weight=1) + self.make_gui() + self.welcome() + self.console_debugging() + + def welcome(self): + '''Displays welcome message''' + self.Welcome = ttk.Label(self.InfoFrame, font='TkDefaultFont 10', + text=WELCOME, wraplength='350', anchor='nw', + justify='left') + self.Welcome.grid(column=0, row=0) + + # binding main keys + def press_return(self, *args): + '''Processing query when "Enter" gets pressed''' + char_query = self.Entry.get() + self.process_query(char_query) + + def select_all(self, *args): + '''Select all text in the text widget. + ''' + # checking which widget has focus + if self.Entry is self.focus_get(): + self.Entry.select_range(0, 'end') + return 'break' + + def rebuild_Query(self): + '''Cleaning up ResultFrame widgets''' + try: + self.Welcome.destroy() + self.NoQuery.destroy() + except: + pass + + def process_query(self, query): + '''Processing entered query''' + self.REVERSE = False + self.rebuild_ResultFrame() + if not query: + self.rebuild_Query() + self.NoQuery = ttk.Label(self.ResultFrame, + font='TkDefaultFont 11', + text='Give me a Char/String please!') + self.NoQuery.grid() + elif self.reverse_query(query): + self.rebuild_Query() + self.ReverseQuery = ttk.Label(self.ResultFrame, + font='TkDefaultFont 11', + text='reverse query') + self.ReverseQuery.grid() + self.REVERSE = True + self.Entry.delete(0, END) + self.Entry.insert(0, query) + query = query[:50] # limiting reverse_query input + uquery, query_info, restored_cache = self.restore_encoded(query) + self.result_inserter(uquery, query_info, restored_cache) + else: + self.Entry.delete(0, END) + self.Entry.insert(0, query) + query = query[:10] # limit query to 20 chars + query_info = self.get_info(query) + result_cache = self.query_dispatcher(query) + self.result_inserter(query, query_info, result_cache) + + def query_dispatcher(self, query): + '''Invoking required converting functions''' + result_cache = [] + check_boxes = (self.isuni, self.isesc, self.isutf8, self.isutf16, + self.isdeci, self.isbin) + + switcher = {0: self.continue_fun, 1: self.get_unicode, 2: self.get_esc, + 3: self.get_utf8, 4: self.get_utf16, 5: self.get_deci, + 6: self.get_bin} + + for func in check_boxes: + result_cache.append(switcher[func.get()](query)) + + return result_cache + + def continue_fun(self, query): + '''Return function''' + return + + def reverse_query(self, query): + '''Checking if query is an actual representation type''' + rgxs = (r'0x.+', r'\\x.+') + if re.match(r'\\u.{3,}', query): + self.OTHER_REPR = False + return True + for rgx in rgxs: + if re.match(rgx, query): + self.OTHER_REPR = True + return True + return False + + def bad_Query(self): + '''Displays a message if reverse query is incorrect''' + try: + self.BadQuery.destroy() + except: + pass + self.BadQuery = ttk.Label(self.ResultFrame, + font='TkDefaultFont 11 bold', + text='incorrect query!') + self.BadQuery.grid() + + def restore_encoded(self, query): + '''Restoring encoded query''' + qinfo = [] + restored_cache = [] + uquery = u'' + if self.OTHER_REPR: + try: + query = query.lstrip('0x|\\x') + query = unichr(int(query, 16)).encode('utf-8') + uquery = re.sub('0', r'\\', unicode(query, 'utf-8')) + except: + self.bad_Query() + else: + try: + uquery = unicode(query, 'utf-8') + uquery = uquery.decode('unicode_escape').split() + except: + self.bad_Query() + + for q in query.split(): + uq = unicode(q, 'utf-8') + if not self.OTHER_REPR: + try: + qinfo.append(unicodedata.name(uq.decode('unicode_escape'))) + except: + self.bad_Query() + else: + try: + qinfo.append(unicodedata.name(uq)) + except: + self.bad_Query() + restored_cache.append(query.encode('utf-8')) + return uquery, qinfo, restored_cache + + def char_cache(self, query): + '''Caching chars into list''' + return [c for c in query] + + def get_info(self, query): + '''Getting unicodedata information on the query''' + u_query = unicode(query) + u_query_info = [unicodedata.name(c) for c in u_query] + return u_query_info + + def get_unicode(self, query): + '''Converting query to unicode code points''' + char_cache = self.char_cache(query) + uni_c = ["U+{:04X}".format(ord(c)) for c in char_cache] + return uni_c + + def get_esc(self, query): + '''Converting query to unicode escapes notation''' + char_cache = self.char_cache(query) + esc_c = ['\u{:04X}'.format(ord(c)) for c in char_cache] + return esc_c + + def get_utf8(self, query): + '''Converting query to utf8 code points''' + char_cache = self.char_cache(query) + utf8_c = [c.encode('hex').upper() for c in char_cache] + return utf8_c + + def get_utf16(self, query): + '''Converting query to utf16 code points''' + char_cache = self.char_cache(query) + utf16_c = [c.encode('utf-16').encode('hex').upper() + for c in char_cache] + return utf16_c + + def get_deci(self, query): + '''Converting query to decimal notation''' + char_cache = self.char_cache(query) + deci_c = [ord(c) for c in char_cache] + return deci_c + + def get_bin(self, query): + '''Converting query to binary notation''' + char_cache = self.char_cache(query) + bin_c = [''.join(format(ord(c), 'b')) for c in char_cache] + return bin_c + + def list_unpacker(self, custom_list): + '''Unpacking lists to strings''' + list_str = '' + for item in custom_list: + list_str = ' '.join([list_str, str(item) + ',']) + return list_str.rstrip(',') + + def text_inserter(self, n, res, query): + '''Inserting text into result frame''' + colors = {0: '#ccccff', 1: '#ccffcc', 2: '#ffcccc', 3: '#ff99ff', + 4: '#ccccff', 5: '#cbcbcb'} + # setting ResText widget length + lengths = {} + try: + lengths[n] = len(str(res[0])) + 3 + except: + lengths[n] = 0 + self.ResText = Text(self.ResultFrame, height=1, + width=len(query)*lengths[n], + font='TkDefaultFont 11', borderwidth=2, + # background=root.cget('bg') + background=colors[n]) + if isinstance(res, list): + ures = self.list_unpacker(res) + elif not self.OTHER_REPR: + ures = unicode(res, 'utf-8') + ures = ures.decode('unicode_escape') + else: + ures = unicode(res, 'utf-8') + self.ResText.insert(1.0, ures) + self.ResText.configure(state='normal', relief='groove') + self.ResText.grid(sticky='w') + + def result_inserter(self, query, query_info, result_cache): + '''Inserting results adding colors into Result widget''' + # inserting char information + for n in range(len(query_info)): + full_q = ' '.join(['"' + query[n] + '" -->', query_info[n]]) + self.Info = ttk.Label(self.InfoFrame, font='TkDefaultFont 10', + text=full_q, wraplength='350', anchor='nw', + justify='left') + self.Info.grid(sticky='w') + + # inserting conversion results, + '''result_cache is a list where [[get_unicode], [get_esc], [get_utf8], + [get_utf16], [get_deci], [get_bin]]''' + for n in range(len(result_cache)): + if not result_cache[n]: + self.text_inserter(n, '', query) + continue + self.text_inserter(n, result_cache[n], query) + + def make_signs_table(self): + '''Creating common sign buttons''' + # button special signs + signs = {0: u'℃', 1: u'°', 2: u'¹', 3: u'²', 4: u'³', 5: u'′', 6: u'″', + 7: u'±', 8: u'∓', 9: u'÷', 10: u'≠', 11: u'≡', 12: u'≤', + 13: u'≥', 14: u'≪', 15: u'≫', 16: u'≃', 17: u'≈', 18: u'√', + 19: u'∛', 20: u'∜', 21: u'½', 22: u'⅓', 23: u'¼', 24: u'¾', + 25: u'⅜', 26: u'‰', 27: u'∝', 28: u'≉', 29: u'≅', 30: u'≇', + 31: u'∣', 32: u'∤', 33: u'£', 34: u'€', 35: u'¥', 36: u'∑', + 37: u'∏', 38: u'∐', 39: u'∈', 40: u'∉', 41: u'∋', 42: u'∌', + 43: u'∅', 44: u'∞', 45: u'∧', 46: u'∨', 47: u'∩', 48: u'∪', + 49: u'⊂', 50: u'⊃', 51: u'⊄', 52: u'⊅', 53: u'⊆', 54: u'⊇', + 55: u'⊈', 56: u'⊉', 57: u'¶', 58: u'·', 59: u'∘', 60: u'◊', + 61: u'¤', 62: u'§', 63: u'π', 64: u'ƒ', 65: u'Δ', 66: u'µ', + 67: u'α', 68: u'ß', 69: u'γ', 70: u'Å', 71: u'´', 72: u'´', + 73: u'¯', 74: u'№', 75: u'©', 76: u'®', 77: u'™', 78: u'℠'} + + # columns range + vbox = {0: 0, + 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 0, + 10: 1, 11: 2, 12: 3, 13: 4, 14: 5, 15: 6, 16: 7, 17: 8, 18: 0, + 19: 1, 20: 2, 21: 3, 22: 4, 23: 5, 24: 6, 25: 7, 26: 8, 27: 0, + 28: 1, 29: 2, 30: 3, 31: 4, 32: 5, 33: 6, 34: 7, 35: 8, 36: 0, + 37: 1, 38: 2, 39: 3, 40: 4, 41: 5, 42: 6, 43: 7, 44: 8, 45: 0, + 46: 1, 47: 2, 48: 3, 49: 4, 50: 5, 51: 6, 52: 7, 53: 8, 54: 0, + 55: 1, 56: 2, 57: 3, 58: 4, 59: 5, 60: 6, 61: 7, 62: 8, 63: 0, + 64: 1, 65: 2, 66: 3, 67: 4, 68: 5, 69: 6, 70: 7, 71: 8, 72: 0, + 73: 1, 74: 2, 75: 3, 76: 4, 77: 5, 78: 6} + + # rows range + hbox = {0: 0, 1: 0, 2: 0, 3: 0, 4: 0, 5: 0, 6: 0, 7: 0, 8: 0, + 9: 1, 10: 1, 11: 1, 12: 1, 13: 1, 14: 1, 15: 1, 16: 1, 17: 1, + 18: 2, 19: 2, 20: 2, 21: 2, 22: 2, 23: 2, 24: 2, 25: 2, 26: 2, + 27: 3, 28: 3, 29: 3, 30: 3, 31: 3, 32: 3, 33: 3, 34: 3, 35: 3, + 36: 4, 37: 4, 38: 4, 39: 4, 40: 4, 41: 4, 42: 4, 43: 4, 44: 4, + 45: 5, 46: 5, 47: 5, 48: 5, 49: 5, 50: 5, 51: 5, 52: 5, 53: 5, + 54: 6, 55: 6, 56: 6, 57: 6, 58: 6, 59: 6, 60: 6, 61: 6, 62: 6, + 63: 7, 64: 7, 65: 7, 66: 7, 67: 7, 68: 7, 69: 7, 70: 7, 71: 7, + 72: 8, 73: 8, 74: 8, 75: 8, 76: 8, 77: 8, 78: 8} + + for n in signs: + ttk.Button(self.SignsFrame, width='2', padding=(1, 1), + text=signs[n], command=lambda sign = signs[n]: + self.process_query(sign)).grid(column=vbox[n], + row=hbox[n]) + + def make_gui(self): + '''Creating main app interface''' + expand = dict(sticky='nsew', pady=1, padx=1) + self.MainFrame = ttk.Frame(self, borderwidth='2', relief='groove') + self.MainFrame.grid(columnspan=2, rowspan=3, **expand) + self.MainFrame.grid_columnconfigure(0, weight=3) + self.MainFrame.grid_columnconfigure(1, weight=1, minsize=205) + self.MainFrame.grid_rowconfigure(0, weight=1) + self.MainFrame.grid_rowconfigure(1, weight=50) + self.MainFrame.grid_rowconfigure(2, weight=1) + + # EntryFrame is a container for Entry widget + self.EntryFrame = ttk.Frame(self.MainFrame, borderwidth='2', + relief='groove') + self.EntryFrame.grid(column=0, row=0, columnspan=1, rowspan=1, + sticky='wne') + self.EntryFrame.grid_columnconfigure(0, weight=1) + self.EntryFrame.grid_rowconfigure(0, weight=1) + + # creating Entry widget inside EntryFrame container + self.Entry = ttk.Entry(self.EntryFrame, font='Tahoma 21') + self.Entry.grid(column=0, row=0, columnspan=1, **expand) + # binding keys + self.Entry.bind('', self.select_all) + self.Entry.bind('', self.press_return, '+') + # works only when entry is focused + self.Entry.focus() + + # Process button container + self.ProcessFrame = ttk.Frame(self.MainFrame, borderwidth='2', + relief='groove') + self.ProcessFrame.grid_columnconfigure(0, weight=1) + self.ProcessFrame.grid_rowconfigure(0, weight=1) + self.ProcessFrame.grid(column=1, row=0, **expand) + + # creating Process button + self.Process = ttk.Button(self.ProcessFrame, padding=(0, 7), + text='Convert', command=self.press_return) + self.Process.grid(column=0, row=0, sticky='we') + + # Check-box container + self.CheckFrame = ttk.Frame(self.MainFrame, borderwidth='2', + relief='groove') + self.CheckFrame.grid_columnconfigure(0, weight=1) + self.CheckFrame.grid(column=1, row=2, **expand) + + # creating Check-boxes + self.isuni = IntVar() + self.CheckUni = ttk.Checkbutton(self.CheckFrame, + text='Unicode (code point)', + onvalue=1, offvalue=0, + variable=self.isuni) + self.CheckUni.grid(**expand) + self.CheckUni.invoke() + + self.isesc = IntVar() + self.CheckEsc = ttk.Checkbutton(self.CheckFrame, + text='Unicode (escaped hex)', + onvalue=2, offvalue=0, + variable=self.isesc) + self.CheckEsc.grid(**expand) + self.CheckEsc.invoke() + + self.isutf8 = IntVar() + self.CheckUTF8 = ttk.Checkbutton(self.CheckFrame, text='UTF-8 (hex)', + onvalue=3, offvalue=0, + variable=self.isutf8) + self.CheckUTF8.grid(**expand) + self.CheckUTF8.invoke() + + self.isutf16 = IntVar() + self.CheckUTF16 = ttk.Checkbutton(self.CheckFrame, text='UTF-16 (hex)', + onvalue=4, offvalue=0, + variable=self.isutf16) + self.CheckUTF16.grid(**expand) + self.CheckUTF16.invoke() + + self.isdeci = IntVar() + self.CheckDeci = ttk.Checkbutton(self.CheckFrame, text='Decimal', + onvalue=5, offvalue=0, + variable=self.isdeci) + self.CheckDeci.grid(**expand) + self.CheckDeci.invoke() + + self.isbin = IntVar() + self.CheckBin = ttk.Checkbutton(self.CheckFrame, text='Binary', + onvalue=6, offvalue=0, + variable=self.isbin) + self.CheckBin.grid(**expand) + self.CheckBin.invoke() + + # Sings button container + self.SignsFrame = ttk.Frame(self.MainFrame, borderwidth='2', + relief='groove') + self.SignsFrame.grid(column=1, row=1, **expand) + + # creating Common signs buttons + self.make_signs_table() + + # Results container + self.rebuild_ResultFrame() + + def rebuild_ResultFrame(self): + '''Refreshing results frame''' + try: + self.ResultFrame.destroy() + self.InfoFrame.destroy() + except: + pass + + # Characters info frame + self.InfoFrame = ttk.Frame(self.MainFrame, borderwidth='2', + relief='groove') + self.InfoFrame.grid(column=0, row=1, sticky='wnse') + + # Convertion results frame + self.ResultFrame = ttk.Frame(self.MainFrame, borderwidth='2', + relief='groove') + self.ResultFrame.grid_columnconfigure(0, weight=1) + self.ResultFrame.grid(column=0, row=2, sticky='wnse') + + def console_debugging(self): + '''Setting utf-8 env for correct cmd output while debugging''' + reload(sys) + sys.setdefaultencoding('utf-8') + sys.stdout = codecs.getwriter('utf8')(sys.stdout) + sys.stderr = codecs.getwriter('utf8')(sys.stderr) + +# Welcome message +WELCOME = '''Charconv 0.1 is a small app that displays input query in \ +various unicode representation formats. + +Choose your format type on the lower right pane. +Enter a string (10 chars max) in the query above \ +and press "Convert" button to see the results. + +You can do a reverse query in \\u, 0x, \\x notation as well.''' + + +# starting main interface loop +if __name__ == "__main__": + root = Tk() + root.title('Charconv 0.1') + root.geometry("570x430") # geometry size when the app is started + root.columnconfigure(0, weight=1) + root.rowconfigure(0, weight=1) + root.resizable(True, True) + root.update() + + # you can use ttk themes here ('clam', 'alt', 'classic', 'default') + # ttk_theme = ttk.Style() + # ttk_theme.theme_use('clam') + + app = Charconv(root) + app.mainloop() + +# TODO