Zmiana podstawy systemu liczbowego kodu znaku. Prosty szyfr
Wstęp
W artykule pokazano, jak zmienić podstawę systemu liczbowego kodu znaku i użyć powstałego zapisu kodów znaków, jako szyfru. Jest to szyfr podstawieniowy o zmiennej długości ciągu zastępującego pojedynczy znak. Można w ten sposób kodować znaki kontrolne, takie jak tabulacja (znak o kodzie 9), para CR+LF (znaki o kodzie 13 i 10), pozostałe znaki kodu ASCII oraz znaki o kodach od 128 do 65535, a więc także znaki narodowe różnych języków.Etapy kodowania na przykładzie słowa ŻUK
![Kodowanie słowa - przykład](http://) ![04 EtapyKodowania.png](https://4programmers.net/uploads/attachment/5c/5c4c21b5c9dc9.png)Przykłady tekstów zaszyfrowanych (podstawa systemu liczbowego 18)
Algorytmy szyfrujący i deszyfrujący - kod C#
namespace NSEncoder
{
class Constants
{
// Używana w programie podstawa systemu liczbowego
// Uwaga: Program będzie działał również po wybraniu
// innej podstawy ze zbioru [2..17]
// Im mniejsza podstawa tym dłuższy zaszyfrowany tekst
public static int Base = 18;
// Cyfry używane przy zmianie podstawy (analogicznie jak w systemie
// szesnastkowym '0'..'9', 'A', 'B',...)
public static string BaseDigits = "0123456789ABCDEFGH";
// Znaki używane do zamiany ostatnich cyfr po których występuje '#'
// Uwaga: musi być ich tyle samo ile cyfr w BaseDigits
// Tu: 18
// Liczba cyfr 18 pozwala na wykorzystanie całego alfabetu
// łacińskiego (w połączeniu z cyframi 0..9)
public static string EndDigitReplacers = "IJKLMNOPQRSTUVWXYZ";
}
}
namespace NSEncoder
{
// Szyfrator
class Encoder
{
// Zamiana liczby dziesiętnej na liczbę o zadanej podstawie
// Tu: podstawa może być od 2 do 18, bo Constants.BaseDigits
// to zbiór cyfr ['0'..'9', 'A'..'H']
static string DecToBase(int decNum, int base_)
{
string s = "";
if (decNum == 0)
{
s = Constants.EndDigitReplacers[0].ToString();
}
else
{
while (decNum > 0)
{
s = Constants.BaseDigits[decNum % base_] + s;
decNum = decNum / base_;
}
}
return s;
}
// Zamiana kodów znaków na liczby o podstawie Constants.Base
// Liczby w zmienionym systemie liczbowym odzielane są znakami '#'
// i łączone w jeden łańcuch znaków
// Tu: Podstawa to 18
static string EncodeCharCodes(string text)
{
string s = "";
for (int i = 0; i < text.Length; i++)
{
s += DecToBase((int)(text[i]), Constants.Base) + '#';
}
return s;
}
// Zamiana par ostania_cyfra-znak_krzyżyk na znaki ['I'..'Z']
// pochodzące z Constants.EndDigitReplacers
// Przykład: kod znaku 'A' to dziesiętnie 65
// po zamianie na system 18-kowy to '3B'
// po złączeniu z '#' to '3B#', a po zamianie 'B#' na 'T'
// zapis kodu znaku to '3T'
static string EncodeEndDigits(string text)
{
for (int i = 0; i < Constants.Base; i++)
{
text = text.Replace(Constants.BaseDigits[i].ToString() + '#',
Constants.EndDigitReplacers[i].ToString());
}
return text;
}
// Szyfrowanie teksu
public static string Encode(string text)
{
text = EncodeCharCodes(text);
text = EncodeEndDigits(text);
return text;
}
}
}
using System.Collections.Generic;
namespace NSEncoder
{
// Deszyfrator
class Decoder
{
// Zamiana liczby o zadanej podstawie na liczbę dziesiętną
static int BaseToDec(string baseNum, int base_)
{
int n = 0;
for (int i = 0; i < baseNum.Length; i++)
{
n = base_ * n + Constants.BaseDigits.IndexOf(baseNum[i]);
}
return n;
}
// Zamiana ostatnich cyfr na pary cyfra-znak_krzyżyk
static string DecodeEndDigits(string text)
{
for (int i = 0; i < Constants.Base; i++)
{
text = text.Replace(Constants.EndDigitReplacers[i].ToString(),
Constants.BaseDigits[i].ToString() + '#');
}
return text;
}
// Zamiana kodów znaków (liczb o podstawie Constants.Base) oddzielonych
// znakami '#' na znaki odszyfrowanego tekstu
static string DecodeCharCodes(string text)
{
List<string> strings = StringHelper.SplitString(text, '#');
string Text = "";
for (int i = 0; i < strings.Count - 1; i++)
{
Text = Text + (char)(BaseToDec(strings[i], Constants.Base));
}
return Text;
}
// Odszyfrowywanie tekstu
public static string Decode(string text)
{
text = DecodeEndDigits(text);
text = DecodeCharCodes(text);
return text;
}
}
}
Funkcja pomocnicza SplitString
Funkcja dzieli tekst z wyróżnionym separatorem (tu: '#') na odrębne ciągi i zapisuje je do listy. ```csharp using System.Collections.Generic;namespace NSEncoder
{
class StringHelper
{
// Zamiana ciągu znaków rozdzielanego znakami splitterChar
// na listę fragmentów tekstu bez separatora
public static List<string> SplitString(string str, char splitterChar)
{
List<string> strings = new List<string>();
while (str.IndexOf(splitterChar) >= 0)
{
int position = str.IndexOf(splitterChar);
strings.Add(str.Substring(0, position));
str = str.Substring(position + 1);
}
strings.Add(str);
return strings;
}
}
}