Преобразование не-ascii символов с помощью Python3
Я хочу задать вопрос о преобразовании текстовых символов в двоичные числа в Python. Я написал программу, которая конвертирует все символы ASCII и некоторые турецкие символы в двоичные числа. Ниже приведены коды этой программы преобразования:
while True:
ASCII_characters_dict = {chr(i): "0" + bin(ord(chr(i)))[2:] for i in range(128)}
for i in ASCII_characters_dict:
if len(ASCII_characters_dict[i]) == 7:
ASCII_characters_dict[i] = "0" + ASCII_characters_dict[i]
elif len(ASCII_characters_dict[i]) == 6:
ASCII_characters_dict[i] = "00" + ASCII_characters_dict[i]
elif len(ASCII_characters_dict[i]) == 5:
ASCII_characters_dict[i] = "000" + ASCII_characters_dict[i]
elif len(ASCII_characters_dict[i]) == 4:
ASCII_characters_dict[i] = "0000" + ASCII_characters_dict[i]
elif len(ASCII_characters_dict[i]) == 3:
ASCII_characters_dict[i] = "00000" + ASCII_characters_dict[i]
elif len(ASCII_characters_dict[i]) == 2:
ASCII_characters_dict[i] = "000000" + ASCII_characters_dict[i]
Turkish_characters = "çÇöÖüÜ"
Turkish_characters_dict = {i: bin(ord(i))[2:] for i in Turkish_characters}
Dictionary = ASCII_characters_dict.copy()
Dictionary.update(Turkish_characters_dict)
başlık = "WELCOME TO THE CONVERTOR"
süs="-"*80
print("\n{}\n\n{}\n".format(süs, başlık.center(80," ")))
seçenekler = "1. To convert text to binary, press '1'.\n2. To convert binary to text, press '2'.\n3. To exit the program, press '3'."
print("{0}\n\n{1}\n\n{0}\n".format(süs, seçenekler))
while True:
seçim = input("Select:")
print("\n{}\n".format(süs))
if seçim=="1":
break
elif seçim=="2":
break
elif seçim == "3":
quit()
else:
print("Warning: Please select one of the given numbers.\n")
while seçim == "1":
altbaşlık = "Convert Text to Binary"
print("{}\n\n{}\n".format(altbaşlık.center(80," "), süs))
text_1 = input("Text:")
text_2 = ""
for i in text_1:
for j in Dictionary:
if i == j:
text_2 += Dictionary[j]
with open("Text_To_Binary.txt","a") as dosya:
dosya.write("\n{0}\n\nBinary: {1}\n\n{0}\n".format(süs, text_2))
print("\n{0}\n\nBinary: {1}\n\n{0}".format(süs, text_2))
message = "1. To continue converting text to binary, press '1'.\n\n3. To return the main page, press '2'.\n\n3. To exit the program, press '3'."
print("\n{}\n\n{}".format(message,süs))
while True:
yeni_seçim_1 = input("\nSelect:")
print("\n{}\n".format(süs))
if yeni_seçim_1 == "1":
break
elif yeni_seçim_1 == "2":
break
elif yeni_seçim_1 == "3":
quit()
else:
print("Warning: Please select one of the given numbers.")
if yeni_seçim_1 == "1":
continue
elif yeni_seçim_1 == "2":
break
while seçim == "2":
altbaşlık = "Convert Binary to Text"
print("{}\n\n{}\n".format(altbaşlık.center(80," "), süs))
text_1 = input("Binary:")
text_2 = ""
list_1 = []
if " " in text_1:
list_1 = text_1.split()
elif " " not in text_1:
for i in range(len(text_1)):
if i % 8 == 0:
text_2 += " "
text_2 += text_1[i]
list_1 = text_2[1:].split(" ")
text_3 = ""
for i in list_1:
for j in Dictionary:
if i == Dictionary[j]:
text_3 += j
with open("Binary_To_Text.txt","a") as dosya:
dosya.write("\n{0}\n\nText: {1}\n\n{0}\n".format(süs, text_3))
print("\n{0}\n\nText: {1}\n\n{0}\n".format(süs, text_3))
message = "1. To continue converting binary to text, press '1'.\n\n3. To return the main page, press '2'.\n\n3. To exit the program, press '3'."
print("{}\n\n{}".format(message,süs))
while True:
yeni_seçim = input("\nSelect:")
print("\n{}\n".format(süs))
if yeni_seçim == "1":
break
elif yeni_seçim == "2":
break
elif yeni_seçim == "3":
quit()
else:
print("Warning: Please select one of the given numbers.")
if yeni_seçim == "2":
break
Этот конвертер может правильно преобразовывать символы "çÇöÖüÜ" в двоичные числа. Я удалил символы "şŞğĞıİ" из списка Turkish_characters_list, потому что программа не может правильно их преобразовать.
Согласно http://roubaixinteractive.com/PlayGround/Binary_Conversion/Binary_To_Text.asp
Двоичные числа символа "ş" - это "001001100010001100110011001101010011000100111011". Когда я копирую это число и записываю его в раздел программы "двоичный в текст", вывод отображается как "& # 351;" <-> (я ставлю пробелы между символами, потому что отображается "ş"). Когда я набираю chr(351), вывод отображает результат в виде символа "ş".
Двоичными числами символа "ş" является bin(351), который равен "0b101011111". Но когда я записываю эти числа в конвертер, программа отображает результат как ноль.
Та же самая проблема может быть замечена в символах "İıİ". Однако символы "çÇöÖüÜ" могут быть преобразованы без проблем.
По данным https://www.binarytranslator.com/
Двоичные числа символа "ş" - это "01011111". Но эти цифры принадлежат символу "_".
Та же самая проблема может быть замечена в символах "İıİ".
Итак, один из моих вопросов о том, почему символы "çÇöÖüÜ" могут быть преобразованы правильно, а символы "şŞğĞıİ" не могут быть преобразованы правильно? Есть ли какое-либо решение этой проблемы, кроме выделения символов "şŞğĞıİ" путем управления ими после шага ввода? Заранее спасибо.
1 ответ
Позвольте мне поделиться тем, что я узнал из этого примера.
Прежде всего, символы ASCII - это символы, которые имеют 8 цифр. 7 из них представляют двоичное число символа, последняя цифра равна "0", что называется "бит четности". (См. https://en.wikipedia.org/wiki/Parity_bit)
Например: двоичное число символа " а" - "1100001", но обычно это число отображается как "01100001". Это отображение называется "Проверка четности". Проверка четности - это тип управления, чтобы узнать, является ли двоичное число нечетным или четным.
Причиной добавления бита четности к этому двоичному номеру является то, что при отправке на другой компьютер этого двоичного числа возможны сбои при передаче. Двоичное число "а" равно 97, что является нечетным числом. Помещая бит четности "0" в это число, этот номер продолжает представлять 97.
Так что символ "а" - это число, определенное в ASCII. Все символы ASCII являются 8-разрядными (означает, что двоичные числа имеют 8 цифр). Но не-ASCII-символы являются 16-разрядными. Давайте посмотрим, почему не-ASCII символы являются 16-битными.
number=ord("a")
#number=97
string=chr(number)
#string="a"
Вышеуказанные коды определяют строку, которая включает только символ "а". Однако, когда пользователь хочет закодировать это число с помощью "utf-8", как указано выше:
number=ord("a")
#number=97
string=chr(number).encode(encoding="utf-8")
#string=b'a'
len(string)
#1
Этот код будет определять строку в шестнадцатеричном формате, если после символа "b" следует символ "\x". Предположим, что символ "ç":
number=ord("ç")
#number=231
string=chr(231).encode(encoding="utf-8")
#string="b'\xc3\xa7'"
len(string)
#2
Последнее значение строки кажется немного странным, но в ней есть реальное значение. Значение "c3a7", которое является шестнадцатеричным числом. Длина символа "а" равна 1. Это означает, что этот номер имеет 8 цифр (битов) и равен 1 байту. Однако длина символа "ç" равна 2. Это означает, что это число имеет 16 цифр (бит) и равно 2 байта.
Итак, давайте посмотрим на двоичное число символа ç:
number=int("c3a7",16)
#number=50087
binary_number_of_character_ç=bin(50087)
#binary_number_of_character_ç=1100001110100111
len(binary_number_of_character_ç)
#16
Таким образом, двоичное число "ç" - это "1100001110100111", которое также обычно отображается как "11000011 10100111".
Если мы изменим всю структуру кода в соответствии с приведенной выше информацией, коды могут быть такими, как показано ниже, которые не дают ошибок при отображении символов, отличных от ascii:
#-----------------------------IMPORTING Fore and init FUNCTIONS FROM COLORAMA MODULE------------------------------------
from colorama import Fore,init
init(autoreset=True)
#--------------------------------------------DICTIONARY FUNCTION--------------------------------------------------------
def dictionary():
ascii_dictionary = {chr(i): bin(i)[2:] for i in range(128)}
for i in ascii_dictionary:
if len(ascii_dictionary[i]) < 8:
count = 8 - len(ascii_dictionary[i])
ascii_dictionary[i] = "".zfill(count) + ascii_dictionary[i]
non_ascii_dictionary = {chr(i): bin(int(bytes(chr(i).encode(encoding="utf-8")).hex(), 16))[2:10] + " " +
bin(int(bytes(chr(i).encode(encoding="utf-8")).hex(), 16))[10:18] for i in range(128, 512)}
dictionary = ascii_dictionary.copy()
dictionary.update(non_ascii_dictionary)
return dictionary
#--------------------------------------------CONVERTER FUNCTIONS--------------------------------------------------------
def convert_text_to_binary():
text_1 = input("Write A Text:")
print(Fore.LIGHTBLUE_EX + "\n{}".format("-" * 80))
return_value = dictionary()
list_1 = [return_value[j] for i in text_1 for j in return_value if i == j]
text_2 = " ".join(list_1)
print(Fore.RED + "\nOutput: " + Fore.GREEN + "{}\n\n".format(text_2) + Fore.LIGHTBLUE_EX + "{}\n".format("-" * 80))
with open("Text.to_Binary.txt", "a", encoding="utf-8") as file:
file.write("{0}\nInput: {2}\n\nOutput: {1}\n{0}".format("\n"+"-"*80+"\n", text_2, text_1))
def convert_binary_to_text():
text_1 = input("Write Binary Numbers:")
print(Fore.LIGHTBLUE_EX + "\n{}".format("-" * 80))
list_1 = text_1.split()
list_2 = [i for i in list_1 if i.startswith("1")]
count = 0
list_3 = []
while count < len(list_2):
list_3.append(" ".join(list_2[count:count + 2]))
count += 2
list_4 = []
count = 0
for i in list_1:
if i.startswith("0"):
list_4.append(i)
elif i.startswith("1"):
list_1.remove(i)
list_4.append(list_3[count])
count += 1
text_2 = ""
return_value = dictionary()
for i in list_4:
for j in return_value:
if i == return_value[j]:
text_2 += j
print(Fore.RED + "\nOutput: " + Fore.GREEN + "{}\n\n".format(text_2) + Fore.LIGHTBLUE_EX + "{}\n".format("-" * 80))
with open("Binary_to_Text.txt", "a", encoding="utf-8") as file:
file.write("{0}\nInput: {2}\n\nOutput: {1}\n{0}".format("\n"+"-"*80+"\n", text_2, text_1))
#------------------------------------------STYLING WITH TEXT CLASS------------------------------------------------------
class text():
def __init__(self,name,style=Fore.LIGHTBLUE_EX+"-"*80):
self.name=name
self.style=style
def title(self):
print("\n{0}\n\n{1}\n\n{0}\n".format(self.style, str(self.name).center(80, " ")))
def paragraph(self):
print("{0}\n\n{1}\n".format(self.name, self.style))
#-----------------------------------------------TEXT INSTANCES----------------------------------------------------------
head = text(Fore.RED + "WELCOME TO THE CONVERTER")
sub_head_1 = text(Fore.RED + "CONVERT TEXT TO BINARY")
sub_head_2 = text(Fore.RED + "CONVERT BINARY TO TEXT")
head_options = text(Fore.RED + "1. " + Fore.GREEN + "To convert text to binary, press '1'.\n\n" +
Fore.RED + "2. " + Fore.GREEN + "To convert binary to text, press '2'.\n\n" +
Fore.RED + "3. " + Fore.GREEN + "To exit the program, press '3'.")
sub_head_options = text(Fore.RED + "1. " + Fore.GREEN + "To continue converting, press '1'\n\n" +
Fore.RED + "2. " + Fore.GREEN + "To return the main page, press '2'.\n\n" +
Fore.RED + "3. " + Fore.GREEN + "To exit the program, press '3'.")
#-----------------------------------------------CHOICE FUNCTION---------------------------------------------------------
def choice():
while True:
select = input("Select:")
if select == "1":
return select
elif select == "2":
return select
elif select == "3":
quit()
else:
print(Fore.RED+"\nWarning: "+Fore.GREEN+"Please select one of the given numbers.\n")
continue
if select == "1" or select == "2":
break
#---------------------------------------BUNDLING PROGRAM PARTS IN FUNCTION----------------------------------------------
def main_program():
while True:
head.title()
head_options.paragraph()
select = choice()
while select == "1":
sub_head_1.title()
convert_text_to_binary()
sub_head_options.paragraph()
new_select = choice()
if new_select == "2":
break
while select == "2":
sub_head_2.title()
convert_binary_to_text()
sub_head_options.paragraph()
new_select = choice()
if new_select == "2":
break
main_program()