Skocz do zawartości
jakozo

w szyfrze cesara, rotacje i dekodowanie ucinają literki

    Rekomendowane odpowiedzi

    jakozo
    Napisano (edytowane)

    Aplikacja wysyła SMSa zakodowanego z powiedzmy rotacją 10, zaszyfrowanie chodzi, ale jeżeli chce to odszyfrować to moja funkcja deszyfrująca odszyfrowuje do pewnego momentu.

    np po wpisaniu całego alfabetu i daniu rotacji 10

    deszyfracja wygląda tak:

    abcdefghijklmnoprstqabcdef

    czyli działa tylko do q

    11 uciana po "u"

    12 uciana po "x"

    Ale jeżeli zakoduje z rotacją 13 to deszyfracja działa na wszystkim

    Możecie spojrzeć na kod ? bo ja nie mogę doszukać błędu.

    Klasa Cipher

    public class Cipher {
    
    private int _rotationAmount = 13;
    private char[] _lowercase = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i',
    							  'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 
    							  's', 't', 'u', 'v', 'w', 'x', 'y', 'z' };
    
    private char[] _uppercase = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I',
    		  					  'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 
    		  					  'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' };
    
    public Cipher(int rotationAmount) {
    	_rotationAmount = rotationAmount;
    }
    
    public String Encrypt(String text) {
    	StringBuilder sb = new StringBuilder();
    
    	for(int c = 0; c < text.length(); c++) {
    		char letter = text.charAt(c);
    
    		if( letter >= 'a' && letter <= _lowercase[_rotationAmount - 1] ) {
    			letter += _rotationAmount;
    		}
    		else if( letter >= _lowercase[_rotationAmount] && letter <= 'z' ) {
    			letter -= _rotationAmount;
    		}
    		else if( letter >= 'A' && letter <= _uppercase[_rotationAmount - 1] ) {
    			letter += _rotationAmount;
    		}
    		else if( letter >= _uppercase[_rotationAmount] && letter <= 'Z' ) {
    			letter -= _rotationAmount;
    		}
    
    		sb.append(letter);
    	}
    
    	return sb.toString();
    }
    
    public String Decrypt(String text) {
    	StringBuilder sb = new StringBuilder();
    
    	for(int c = 0; c < text.length(); c++) {
    		char letter = text.charAt(c);
    
    		if( letter >= 'a' && letter <= _lowercase[_rotationAmount - 1] ) {
    			letter += _rotationAmount;
    		}
    		else if( letter >= _lowercase[_rotationAmount] && letter <= 'z' ) {
    			letter -= _rotationAmount;
    		}
    		else if( letter >= 'A' && letter <= _uppercase[_rotationAmount - 1] ) {
    			letter += _rotationAmount;
    		}
    		else if( letter >= _uppercase[_rotationAmount] && letter <= 'Z' ) {
    			letter -= _rotationAmount;
    		}
    
    		sb.append(letter);
    	}
    
    	return sb.toString();
    }
    
    }

    w następnej klasie pobieram sobie rotacje, która chce ze spinnera

    private Cipher _cipher = null;
    private void SetRotationAmount(String selectedText) {
    
    if (selectedText == null || selectedText == "")
    	return;			
    
    Log.i("print", selectedText);
    
    if( selectedText.equalsIgnoreCase("Rotation 10")) {
    	_cipher = new Cipher(10);
    }
    else if(selectedText.equalsIgnoreCase("Rotation 11")) {
    	_cipher = new Cipher(11);
    }
    else if( selectedText.equalsIgnoreCase("Rotation 12")) {
    	_cipher = new Cipher(12);
    }
    else if( selectedText.equalsIgnoreCase("Rotation 13")) {
    	_cipher = new Cipher(13);
    }
    
    }
    
    
           Spinner rotationSpinner = (Spinner)findViewById(R.id.spinnerRotationAmount);
       	ArrayAdapter adapter = ArrayAdapter.createFromResource(
       			this, R.array.rotation_list, android.R.layout.simple_spinner_item);
       	adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
       	rotationSpinner.setAdapter(adapter);
    
       	rotationSpinner.setOnItemSelectedListener(new OnItemSelectedListener() {
    
    		public void onItemSelected(AdapterView<?> arg0, View arg1,
    				int arg2, long arg3) {
    			// TODO Auto-generated method stub
    			SetRotationAmount(arg0.getSelectedItem().toString());
    		}
    
    		public void onNothingSelected(AdapterView<?> arg0) {
    			// TODO Auto-generated method stub
    
    		}
    	});
    
    // moje dwa buttony do encode i decode 
    Button encryptButton = (Button)findViewById(R.id.koduj);
         	encryptButton.setOnClickListener(new View.OnClickListener() {
    
     			public void onClick(View v) {
     				EditText textBox = getEditTextObject();
     				textBox.setText(_cipher.Encrypt(textBox.getText().toString()));				
     			}
     		});
    
         	Button decryptButton = (Button)findViewById(R.id.odkoduj);
         	decryptButton.setOnClickListener(new View.OnClickListener() {
    
     			public void onClick(View v) {
     				EditText textBox = getEditTextObject();
     				textBox.setText(_cipher.Decrypt(textBox.getText().toString()));				
     			}
     		});
    

    Dlaczego tak się dzieje ze rotacja 13 chodzi a gdy wybiorę rotacje 10 11 lub 12 to ucina mi dekodowanie po jakiejś literze?

    Edytowane przez jakozo

    Udostępnij tę odpowiedź


    Odnośnik do odpowiedzi
    Udostępnij na innych stronach
    Napisano (edytowane)

    Ogółem trochę zagmatwane. Problem jest m. in. z letter <= _lowercase[_rotationAmount - 1]. Czyli sprawdzasz ten warunek i w zależności albo dodasz rotację albo odejmiesz. W takim wypadku sprawdzi się tylko, jeśli rotacja będzie środkiem, czyli 13 (alfabet ma 26 liter). Jak dasz np. 10 to mniej liter będzie się dodawać a więcej odejmować, co w ostateczności się zupełnie popsuje im dalej od 13 i w którymś momencie będzie ucinać.

    Tu masz myślę, że poprawny kod.

    	public String encrypt(String text) {
    	StringBuilder sb = new StringBuilder();
    
    	for(int c = 0; c < text.length(); c++) {
    		char letter = text.charAt(c);
    
    		if (letter >= 'a' && letter <= 'z') {
    			letter = (char)((((letter-'a')+_rotationAmount)%26)+'a');
    		} else if (letter >= 'A' && letter <= 'Z') {
    			letter = (char)((((letter-'A')+_rotationAmount)%26)+'A');
    		}
    
    		sb.append(letter);
    	}
    
    	return sb.toString();
    }
    
    public String decrypt(String text) {
    	StringBuilder sb = new StringBuilder();
    
    	for(int c = 0; c < text.length(); c++) {
    		char letter = text.charAt(c);
    
    		if (letter >= 'a' && letter <= 'z') {
    			letter = (char)((((letter-'a')-_rotationAmount+26)%26)+'a');
    		} else if (letter >= 'A' && letter <= 'Z') {
    			letter = (char)((((letter-'A')-_rotationAmount+26)%26)+'A');
    		}
    
    		sb.append(letter);
    	}
    
    	return sb.toString();
    }

    Edytowane przez Dzakus
    Dłuższe kody w spoiler

    Udostępnij tę odpowiedź


    Odnośnik do odpowiedzi
    Udostępnij na innych stronach
    Dzakus
    Napisano (edytowane)

    Tutaj prawdopodobnie szybsza wersja

    package algorytmy;
    
    public class SzyfrCezara {
    private int mRotation;
    
    public SzyfrCezara(int rotation) {
    	this.mRotation = rotation;
    }
    
    public int getRotation() {
    	return mRotation;
    }
    
    public void setRotation(int rotation) {
    	this.mRotation = rotation;
    }
    
    public String crypt(String text) {
    	return cryptOrEncrypt(text, mRotation);
    }
    
    public String decrypt(String text) {
    	return cryptOrEncrypt(text, -mRotation);
    }
    
    private static String cryptOrEncrypt(String text, int rotation) {
    	char[] arr = text.toCharArray();
    	for (int i = 0; i < arr.length; i++) {
    		if (arr[i] >= 'a' && arr[i] <= 'z') {
    			arr[i] = (char) ((((arr[i] - 'a') + rotation + 26) % 26) + 'a');
    		} else if (arr[i] >= 'A' && arr[i] >= 'Z') {
    			arr[i] = (char) ((((arr[i] - 'A') + rotation + 26) % 26) + 'A');
    		}
    	}
    	return new String(arr);
    }
    
    public static void main(String[] args) {
    	if (args.length < 2) {
    		System.out.println("SzyfrCezara <rotation> <text>");
    		return;
    	}
    
    	int rotation = Integer.parseInt(args[0]);
    	String text = args[1];
    	SzyfrCezara cipher = new SzyfrCezara(rotation);
    	System.out.println("decrypt: " + cipher.decrypt(text));
    	System.out.println("crypt: " + cipher.crypt(text));
    
    	assert cipher.crypt(cipher.decrypt(text)).equals(text);
    }
    
    }
    

    Edytowane przez Dzakus

    Udostępnij tę odpowiedź


    Odnośnik do odpowiedzi
    Udostępnij na innych stronach
    Dzakus
    Napisano (edytowane)

    Ponieważ nie korzysta z StringBuilder, a więc nie ma zabawy z powiększanie wewnętrznego bufforu i innych zabaw. StringBuilder wewnętrznie korzysta również z tablicy itd, a tutaj jest z góry ustalony rozmiar tablicy. Przy każdym append wykonuje się m.in. wewnętrzny if sprawdzający, czy trzeba powiększyć buffor i ogólnie narzut nie potrzebny spwodowany klasą StringBuilder. Sam skok do innej metody już jest narzutem, a w mojej implementacji wykorzystuje się tylko wewnętrzne instrukcje maszyny wirtualnej.

    Kod klasy StringBuilder: https://android.googlesource.com/platform/libcore.git/+/android-4.2.2_r1/luni/src/main/java/java/lang/AbstractStringBuilder.java

    Jeszcze inna implementacja, która obsługuje własny alfabet w tym wypadku polski alfabet.

    package algorytmy;
    
    import java.util.Arrays;
    import java.util.List;
    
    public class SzyfrCezara {
    private static final List<Character> DEFAULT_SMALL_LETTERS = Arrays.asList(
    		'a', 'ą', 'b', 'c', 'ć', 'd', 'e', 'ę', 'f', 'g', 'h', 'i', 'j',
    		'k', 'l', 'ł', 'm', 'n', 'ń', 'o', 'ó', 'p', 'r', 's', 'ś', 't',
    		'u', 'w', 'y', 'z', 'ź', 'ż');
    
    private static final List<Character> DEFAULT_BIG_LETTERS = Arrays.asList(
    		'A', 'Ą', 'B', 'C', 'Ć', 'D', 'E', 'Ę', 'F', 'G', 'H', 'I', 'J',
    		'K', 'L', 'Ł', 'M', 'N', 'Ń', 'O', 'Ó', 'P', 'R', 'S', 'Ś', 'T',
    		'U', 'W', 'Y', 'Z', 'Ź', 'Ż');
    
    private final List<Character> mListSmallLetters;
    private final List<Character> mListBigLetters;
    private int mRotation;
    
    public SzyfrCezara(int rotation) {
    	this(rotation, DEFAULT_SMALL_LETTERS, DEFAULT_BIG_LETTERS);
    }
    
    public SzyfrCezara(int rotation, List<Character> smallLetters,
    		List<Character> bigletters) {
    	this.mListSmallLetters = smallLetters;
    	this.mListBigLetters = bigletters;
    	setRotation(rotation);
    }
    
    public int getRotation() {
    	return mRotation;
    }
    
    public void setRotation(int rotation) {
    	if (rotation > mListSmallLetters.size()
    			|| rotation > mListBigLetters.size() || rotation < 0)
    		throw new IllegalArgumentException();
    	this.mRotation = rotation;
    }
    
    public String crypt(String text) {
    	return cryptOrEncrypt(text, mRotation);
    }
    
    public String decrypt(String text) {
    	return cryptOrEncrypt(text, -mRotation);
    }
    
    private String cryptOrEncrypt(String text, int rotation) {
    	char[] arr = text.toCharArray();
    	int countSmallLetters = mListSmallLetters.size();
    	int countBigLetters = mListBigLetters.size();
    	for (int i = 0; i < arr.length; i++) {
    		int indexSmall = mListSmallLetters.indexOf(arr[i]);
    		if (indexSmall >= 0) {
    			arr[i] = mListSmallLetters
    					.get((countSmallLetters + (indexSmall + rotation))
    							% countSmallLetters);
    			continue;
    		}
    		int indexBig = mListBigLetters.indexOf(arr[i]);
    		if (indexBig >= 0) {
    			arr[i] = mListBigLetters
    					.get((countBigLetters + (indexBig + rotation))
    							% countBigLetters);
    			continue;
    		}
    	}
    	return new String(arr);
    }
    
    public static void main(String[] args) {
    	if (args.length < 2) {
    		System.out.println("SzyfrCezara <rotation> <text>");
    		return;
    	}
    
    	int rotation = Integer.parseInt(args[0]);
    	String text = args[1];
    	// int rotation = 55;
    	// String text = "BBB";
    	SzyfrCezara cipher = new SzyfrCezara(rotation);
    	System.out.println("decrypt: " + cipher.decrypt(text));
    	System.out.println("crypt: " + cipher.crypt(text));
    
    	assert cipher.crypt(cipher.decrypt(text)).equals(text);
    }
    
    }
    
    

    ---------- Post dołączono o 20:07 ---------- Poprzedni post napisano o 12:48 ----------

    Analiza szybkości działania każdego z algorytmów: https://docs.google.com/spreadsheets/d/1MYLaKgdbPGEKTnERm5a_NtA_82_1N8sduZ0SSx9HrDk/edit?usp=sharing (uwaga. Jest kilka arkuszy)

    Edytowane przez Dzakus

    Udostępnij tę odpowiedź


    Odnośnik do odpowiedzi
    Udostępnij na innych stronach

    Jeśli chcesz dodać odpowiedź, zaloguj się lub zarejestruj nowe konto

    Jedynie zarejestrowani użytkownicy mogą komentować zawartość tej strony.

    Zarejestruj nowe konto

    Załóż nowe konto. To bardzo proste!

    Zarejestruj się

    Zaloguj się

    Posiadasz już konto? Zaloguj się poniżej.

    Zaloguj się

    • Przeglądający   0 użytkowników

      Brak zarejestrowanych użytkowników przeglądających tę stronę.