Advertisement
Guest User

Untitled

a guest
Nov 15th, 2019
116
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 9.90 KB | None | 0 0
  1. # importy bibliotek, pandas to operacje na macierzach, argparse to przyjmowanie argumentow z commandlina, sys do wychodzenia w razie zlego pliku, logging do ustawiania czy program ma pisac co robie (opcja --verbose (-v)), re to regexpy - wyrazenia regularne do weryfikacji czy inputem jest niepusty numer w sys, dwojkowym
  2. import pandas as pd
  3. import argparse
  4. import sys
  5. import logging as log
  6. import re
  7.  
  8. # definiuje argumenty przyjmowane przez program
  9. parser = argparse.ArgumentParser(description="Program encodes given sentence to binary format using ANS encoding")
  10. parser.add_argument("-i", "--interactive", action="store_true", help="Launch program in interactive mode")
  11. parser.add_argument("-t", "--encoding-table", metavar="FILE_NAME", nargs="?", default="",
  12.     help="Path to encoding table. Encoding table should be csv file, comma separated, with characters in first row and '-' if no value is available for given cell.")
  13. parser.add_argument("-e", "--encoding-sequence", nargs="?", default="", help="Starting encoding sequence in binary")
  14. parser.add_argument("-s", "--sentence", nargs="?", default="", help="Sentence to be encoded")
  15. parser.add_argument("-v", "--verbose", action="store_true", help="Set output to verbose mode, so algorithm logs what its doing")
  16.  
  17. args = parser.parse_args() # zczytanie argumentów z wiersza polecen
  18.  
  19. if(args.verbose): # ustawienie poziomu logowania w zaleznosci czy jest opcja verbose ustawiona
  20.     log.basicConfig(format="%(message)s", level=log.DEBUG)
  21. else:
  22.     log.basicConfig(format="%(message)s", level=log.WARN)
  23.  
  24.  
  25. # funkcja przyjmująca znak i dataframe (dataframe to macierz)
  26. def get_encoding_list(character, dataframe):
  27.     encoding_list = dataframe[character].tolist() # pobiera z macierzy kolumnę o nazwie podanego znaku i robi z niej liste (bo domyślnie jest to obiekt Series - czyli taki wektor)
  28.  
  29.     for x in encoding_list: # przechodzi po całej liście encoding list testujac znaki
  30.         try:
  31.             if(x != "-"): # jesli znak nie jest pauza to sproboj zrzutowac go na liczbe calkowita
  32.                 int(x)
  33.         except ValueError: # jesli znak wywali blad przy konwersji ze stringa na inta (czyli nim nie jest) to wypisz blad i wyjdz
  34.             print("Error, found character '" + str(x) + "' in csv file. In column '" + character + "'")
  35.             if(str(x) == "nan"): # nan to bedzie pusty znak
  36.                 print("Search for empty columns in file (,,)")
  37.             print("\nFaulty column values: " + encoding_list)
  38.             sys.exit()
  39.  
  40.     return [int(x) for x in encoding_list if x != "-"] # list comprehension w pythonie - skoro tu doszlismy to mozemy spokojnie zrzutowac cala liste znakow na liste liczb calkowitych wylaczajac myslniki (mozna to czytac jako dla kazdego znaku w encoding_list ktory jest rozny od '-' zrzutuj go na inta)
  41.  
  42. # funkcja zamieniajaca liczbe dziesietna na stringa binarnego
  43. def tobin(x):
  44.     return "{:b}".format(x)
  45.  
  46. # i na odwrot
  47. def frombin(x):
  48.     return int(x, 2)
  49.  
  50. #
  51. def get_next_encoding(encoding_list, encoding_sequence):
  52.     encoded_sequence = ""
  53.     log.debug("Trying to get index " + encoding_sequence + " (" + str(frombin(encoding_sequence)) + ") from character column that have " + str(len(encoding_list)) +  " elements.")
  54.    
  55.     while(frombin(encoding_sequence) >= len(encoding_list)): # petla dodaje nowe kolejne znaki do encoded_sequence dopoki ilosc zer/jedynek w encoding_sequence nie przekroczy ilosci elementow w encoding_list
  56.         encoded_sequence += encoding_sequence[-1] # dodaje do encoded_sequence ostatni element encoding_sequence
  57.         encoding_sequence = encoding_sequence[:-1] # usuwa z encoding_sequence ostatni element
  58.  
  59.     encoded_sequence = encoded_sequence[::-1] # odwraca listę
  60.  
  61.     if(encoded_sequence == ""):
  62.         log.debug("Removed nothing from sequence, found " + str(encoding_list[frombin(encoding_sequence) - 1]) + " at index " + encoding_sequence + " (" + str(frombin(encoding_sequence)) + ")")
  63.     else:
  64.         log.debug("Removed " + encoded_sequence + " from sequence and found " + str(tobin(encoding_list[frombin(encoding_sequence) - 1])) + " (" + str(encoding_list[frombin(encoding_sequence) - 1]) + ") at index " + encoding_sequence + " (" + str(frombin(encoding_sequence)) + ")")
  65.    
  66.     return encoded_sequence, tobin(encoding_list[frombin(encoding_sequence) - 1]) # zwracamy tablicę 2 elementowa gdzie 1 element to encoded_sequence, a drugi to encoding_sequence pomniejszony o 1 (zwracany w formie stringa zer/jedynek)
  67.  
  68. def load_table(file_name): # pobiera dane z pliku csv
  69.     df = pd.read_csv(file_name, dtype=str) # wczytanie csv do macierzy
  70.     encoding_dict = {character:get_encoding_list(character, df) for character in list(df)} # stworzenia slownika gdzie klucz to znak a wartosc to jego kodowanie
  71.     log.debug("Characters loaded: " + str([x[0] for x in encoding_dict.items()]))
  72.     return encoding_dict
  73.  
  74. def encode(encoding_dict, sentence, starting_sequence): # funkcja kodujaca podanny tekst przy uzyciu slownika i poczatkowej sekwencji
  75.     log.debug("Starting encoding '" + sentence + "' with sequence " + starting_sequence)
  76.  
  77.     sentence_encoded = ""
  78.     encoding_sequence = starting_sequence
  79.  
  80.     for character in sentence: # przechodzi po kazdym znaku po kolei w sekwencji
  81.         log.debug("Encoding character " + character)
  82.         character_encoded, encoding_sequence = get_next_encoding(encoding_dict[character], encoding_sequence) # wywolanie funcji get_next_encoding zwraca 2 rzeczy na raz, mozna to robic w pythonie
  83.         sentence_encoded += character_encoded # konkatenacja zakodowanego znaku do ogolnego ciagu kodowania
  84.         log.debug("Current encoded sequence is " + (sentence_encoded if sentence_encoded else "empty"))
  85.     log.debug("Adding last sequence (" + encoding_sequence + ") to the result")
  86.     sentence_encoded += encoding_sequence
  87.     log.debug("Current encoded sequence is " + (sentence_encoded if sentence_encoded else "empty"))
  88.  
  89.     log.debug("Encoding finished")
  90.     return sentence_encoded
  91.  
  92. def get_user_input(prompt, default_value): # funkcja do pobierania danych od uzytkownika w wersji interaktywnej, nic ciekawego
  93.     if(default_value == ""):
  94.         print(prompt)
  95.         return input(), True
  96.     else:
  97.         print(prompt + "(default '" + default_value + "') ")
  98.         user_input = input()
  99.         if(user_input != ""):
  100.             return user_input, True
  101.         else:
  102.             return default_value, False
  103.  
  104. def check_sentence_characters(available_characters, sentence): # funkcja sprawdza czy w sentence sa uzywane znaki tylko zawarte w loscie available_characters
  105.     for character in sentence:
  106.         if character not in available_characters:
  107.             return False
  108.     return True
  109.  
  110. def interactive_encoding(): # wersja interaktywna, czyli zamiast podac przy wywolaniu to sobie wpisujemy po kolei co tam rząda program
  111.     file_name = ""
  112.     encoding_sequence = ""
  113.     sentence = ""
  114.     encoding_dict = {}
  115.     while True:
  116.         while True:
  117.             file_name, changed = get_user_input("Enter encoding table path: ", file_name)
  118.             if(changed):
  119.                 print("Loading file...")
  120.             try:
  121.                 encoding_dict = load_table(file_name)
  122.                 break
  123.             except FileNotFoundError:
  124.                 print("File '" + file_name + "' not found. Please check file path.")
  125.                 file_name = ""
  126.         encoding_sequence, _ = get_user_input("Enter starting encoding sequence in binary: ", encoding_sequence)
  127.         sentence, _ = get_user_input("Enter sentence to encode: ", sentence)
  128.         if(not re.match("[01]+", encoding_sequence)):
  129.             print("ERROR: Starting sequence should be non-empty binary number. Skipping encoding. Please enter valid starting sequence.")
  130.             continue
  131.         if(sentence == ""):
  132.             print("WARNING: sentence to encode is empty")
  133.         if(not check_sentence_characters([x[0] for x in encoding_dict.items()], sentence)):
  134.             print("ERROR: sentence contains chracters not available in encoding table. Please note its case sensitive.")
  135.             continue
  136.         print("Encoded sentence: " + encode(encoding_dict, sentence, encoding_sequence) + "\n\n")
  137.  
  138. if(args.interactive): # tutaj zaczyna sie glowne wywolanie programu
  139.     interactive_encoding() # jesli wersja interaktywna to wywolac wersje interaktywna xD
  140. elif(len(sys.argv) == 1): # jak jest za malo argumentow to dochodzimy do wniosku ze uzytkownik nie wie co robi i  i tak odpalamy wersje interaktywna
  141.     print("Warning: no command line arguments, falling back to interactive mode.\n" +
  142.         "Please use -i option to launch interactive mode without warnings")
  143.     interactive_encoding()
  144. else: # a jak juz podaje jakies argumenty no to jazda z wersja standardowa
  145.     encoding_dict = {}
  146.     try:
  147.         encoding_dict = load_table(args.encoding_table)
  148.     except FileNotFoundError:
  149.         print("File '" + args.encoding_table + "' not found. Please check file path.")
  150.         exit()
  151.     if(not re.match("[01]+", args.encoding_sequence)): # sprawdzenie czy podany encoding_sequence zawiera same zera i jedynki i jest niepusty przy uzyciu wyrazenia regularnego [01]+ ktore oznacza "ciag ma zawierać jedno lub wiecej (+) wystapienie znakow z grupy 0,1 ([] to ozznaczenie grupy)"
  152.         print("ERROR: Starting sequence should be non-empty binary number. Skipping encoding. Please enter valid starting sequence.")
  153.         exit()
  154.     if(args.sentence == ""):
  155.         print("WARNING: sentence to encode is empty")
  156.     if(not check_sentence_characters([x[0] for x in encoding_dict.items()], args.sentence)): # [x[0] for x in encoding_dict.items()] konwertuje encoding_dict na liste kluczy słownika, jestem dzbanem bo jest metoda .keys(), nie wiem czemu jej nie uzylem
  157.         print("ERROR: sentence contains chracters not available in encoding table. Please note its case sensitive.")
  158.         exit()
  159.     print(encode(encoding_dict, args.sentence, args.encoding_sequence))
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement