Substring w szyfrze - problem

0

Witam
Ostatnio przerzucam się na C++ (w Visual Studio) i teraz staram się napisać aplikację do szyfrowania. Mam problem z szyfrem Bacona a dokładnie z jego deszyfracją. Krótko mówiąc polega on na zamianie konkretnych liter w ciągi złożone z 'a' i 'b' np. "a" -> "aaaaa", "b" -> "aaaab" itp. Znaki poza literami pozostają nie zmienione.

O ile szyfrowanie poszło mi dość dobrze to mam problem jak to odczytać. Moja koncepcja, aby sprawdzać 5 znaków z wszystkimi możliwymi kombinacjami oznaczającymi litery nie chce działać. Kompiluje się, ale nawet próba odszyfrowania "aaaaa" wyrzuca komunikat błędu, który [jak mi się wydaje] mówi o przekroczeniu tablicy.

Fragment kodu, który za to odpowiada (na razie tylko litery a i b oraz inne znaki uwzględniłem - chciałem switch'em ale nie obsługuje string'ów):

{
richTextBox1->Text = ""; //czyszczenie miejsca zapisania rozszyfrowanego kodu
System::String^ tekscik = richTextBox2->Text;
int dl = tekscik->Length;
System::String^ frag;
for (int i=0; i<dl;)
        {
	frag = tekscik->Substring(i, 5);
	if (frag == "aaaaa") {richTextBox1->Text += "a"; i=i+5;}
	if (frag == "aaaab") {richTextBox1->Text += "b"; i=i+5;} else {richTextBox1->Text += tekscik[i].ToString(); i=i+1;}
	}
		 } 
0

tak na szybko, wszystkie twoje napisy powinny być unikodowe, tj. L"aaaaa"
Zawsze gdy używasz String^, literał powinien być z L przed cudzysłowem.

0
if (frag == L"aaaaa") {richTextBox1->Text += "a"; i=i+5;}
if (frag == L"aaaab") {richTextBox1->Text += "b"; i=i+5;} 

Jeśli dobrze rozumiem chodzi o coś takiego. Ale nie wyklucza to wcześniejszego błędu :/

1
frag = tekscik->Substring(i, 5);

Pobierasz pięć znaków począwszy od pozycji i, a przecież wcale nie musi być tyle liter pozostałych (np. na ostatniej pozycji jest tylko jedna), a nawet cały napis może być krótszy niż pięć znaków.

0

Po uwzględnieniu porad Azarien'a (dziękuję) udaje się odszyfrować pewne ciągi, ale to nie jest działa jak powinno. (Nie zauważyłem różnicy 'unicodowych' ciągów, ani takie nie działają, ani drugie)

Kod wygląda teraz następująco:

System::String^ tekscik = richTextBox2->Text + "^"; // ((1))
int dl = tekscik->Length;
System::String^ frag;
for (int i=0; i<dl;)
{
if (dl>=i+5)
{
frag = tekscik->Substring(i, 5);
if (frag == L"aaaaa") {richTextBox1->Text += "a"; i=i+5;}
if (frag == L"aaaab") {richTextBox1->Text += "b"; i=i+5;}
if (frag == L"aaaba") {richTextBox1->Text += "c"; i=i+5;}
if (frag == L"aaabb") {richTextBox1->Text += "d"; i=i+5;}
//[....] kolejne znaki i ich kody
if (frag == L"BABBA") {richTextBox1->Text += "Y"; i=i+5;}
if (frag == L"BABBB") {richTextBox1->Text += "Z"; i=i+5;} else {richTextBox1->Text += tekscik[i].ToString(); i=i+1;}
}
else {richTextBox1->Text += tekscik[i].ToString(); i=i+1;}
}
 

Problemy jakie teraz z tym mam to następujące:

  1. Rozkodowywanie ciągu "aaaaa" jest niemożliwe, jako, że wyrzuca błąd odwoływania się za tablicę. poradziłem sobie 'partyzancko' - ((1))
  2. Zaszyfrowanie (które działa) 4 znaków "a", a potem ich rozkodowanie daje "aaaaaaaaa" (9 x "a", czyli rozkodował tylko 3 ciągi).
  3. Zakodowanie "szyfr", a potem jego rozkodowanie daje wynik "sbqabsabr", natomiast zaszyfrowanie "s z y f r" i jego odkodowanie daje dobry efekt.

Wydaje mi się, że są to już tylko błędy logiczne, ale za wszelkie (nawet małe sugestie czy pomysły) będę wdzięczny. :)
Pozdrawiam
Piotrek - franiis

1

nie tłumaczy to dlaczego: 1) Wywala się przy próbie odszyfrowania "aaaaa"

Ponieważ w pętli jedziesz po całym stringu, to dla stringa takiego:

Ala ma kota
w poszczególnych krokach próbujesz czytać takie 5-literowe podciągi:

'Ala m'
'la ma'
'a ma '
' ma k'
'ma ko'
'a kot'
' kota'
'kota☠'
'ota☠☠'
'ta☠☠☠'
'a☠☠☠☠'
0

To się zgadza. Ale po poprawkach, które opisałem uwzględniam już to. więc wyglądałoby to tak (nie zastosuję zdania, "Ala ma kota" - gdyż nie pasuje):

Tekst: AAAAAdomAAAAAxx

  1. AAAAA - wypisuje "A" i dodaje 5 do przelicznika,
  2. sprawdza domAA, ale że nie ma takiego kodu to wypisuje "d" i dodaje 1 do przelicznika,
  3. sprawdza omAAA, analogicznie jak w 2),
  4. sprawdza mAAAA, analogicznie jak wyżej,
  5. sprawdza AAAAA i wypisuje "A" oraz dodaje 5 po przelicznika.
  6. długość ciągu pomniejszona o aktualne miejsce odczytu jest już mniejsza od 5, więc po prostu przepisuje kolejny znak x (wiem, że nic nie jest tu zakodowane).
  7. analogicznie jak wyżej x

Tak to powinno działać (w moim zamierzeniu), ale coś jest nie tak, jak wcześniej opisałem

0

Wychodzisz poza zakres tablicy dlatego, że po znalezieniu pasującego wzorca nie przechodzisz do następnego obiegu pętli tylko kontynuujesz kolejne porównania.
Zamień if'y na if..else'y

if (frag == L"aaaaa") {richTextBox1->Text += "a"; i=i+5;}
else if (frag == L"aaaab") {richTextBox1->Text += "b"; i=i+5; }
else if...

A tak w ogóle to użyj pętli i tablicy czy jakiegoś kontenera zamiast się powtarzać X razy!

Poza tym zamiast sprawdzać zakres wewnątrz pętli:

for (int i=0; i<dl;)
{
    if (dl>=i+5) ...

powinieneś po prostu iterować po właściwym zakresie:

for (int i = 0; i + 5 < dl; )
{
    ...

no chyba, że długość wzorców może być różna wtedy trzeba to inaczej rozwiązać.

Jeśli wzorców będzie dużo a chciałbyś przyspieszyć algorytm to do ich przechowywania/wyszukiwania użyj drzewa słownikowego czy hashtablicy np. System::HashSet. W przypadku wzorców o różnej długości najbardziej optymalne powinno być drzewo słownikowe, tyle że musiałbyś je sam zaimplementować lub użyć dodatkowej biblioteki.

0

Dzięki wielkie za poradę z "if else" - wszystko działa jak powinno. Co do dalszych pomysłów, to:

  1. Zamiana zakresu for spowoduje, że ostanie znaki, jeśli nie będą kodowane, to je pozostawi nie przenosząc ich do tekstu jawnego.
  2. Długości ciągów wynoszą albo 1 albo 5. Kodowane są tylko 5-cio znakowe. Liczba takich kombinacji to 50-52 (zależnie czy trwa kodowanie czy odkodowywanie). Już mam zapisany tak kod, więc chyba nie potrzebuję zmieniać tego koniecznie. Poza tym średnio 25 porównań to nie jest chyba liczba, która załamie zdolności algorytmu.

Bardzo dziękuję za pomoc :)
Chyba można zamknąć.

0

ad 1) po prostu dopisz do wyniku resztę która ci zostanie

1 użytkowników online, w tym zalogowanych: 0, gości: 1