Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Алгоритмы > простенький алгоритм для шифрования


Автор: Qawra 23.12.2009, 00:01
Написала " своими словами " простенький алгоритм для шифрования .
Правда он на любом input даёт один и тот же output .
Посмотрите пожайлуста "свежим взглядом " в чём проблема :
Код

public class CeasarCipher {

    public static final int numberOfUsedLetters = 26; //use only English alphabet in uppercase
    public static final char[] alphabet = {'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'};
    // uses  rotation around array to enciphing and oposite rotation to deciphing
    protected static char[] encryptArray = new char[numberOfUsedLetters];
    protected static char[] decryptArray = new char[numberOfUsedLetters];
    public static String result;

    public static String enciphing(String input, int shift) {

        input.toUpperCase(); //convert all letters to UpperCase for comparison

        char[] plaintext = new char[input.length()];
        char[] ciphertext = new char[input.length()]; // assume that there will be no punctuation or empty spaces to remove
        result = ""; //because ciphers can run simultaneosly - "result" could change value

        // rotate alphabet by number of places entered by user
        for (int i = 0; i < numberOfUsedLetters ; i++) {
            encryptArray[i] = alphabet[(i + shift) % numberOfUsedLetters];
        }
        //  remove any punctuation and empty spaces from String entered by user
        int c = 0;//will be used as index
        for (int i = 0; i < input.length(); i++) // we check all elements of entered String
        {
            if (input.charAt(i) >= 'A' && input.charAt(i) <= 'Z') { // only letters we copy to plaintext array for enciphing
                plaintext[c] = input.charAt(i);
                c++;
            }
        }
        // actually enciphing starts

        for (int x = 0; x < plaintext.length; x++) {
            for (int y = 0; y < alphabet.length; y++) {
                if (plaintext[x] == alphabet[y]) {
                    ciphertext[c] = encryptArray[y];
                }
            }
        }
        // form String from array of char
        StringBuilder ciphertextBuilder = new StringBuilder();

        for (int j = 0; j < ciphertext.length; j++) {
            ciphertextBuilder = ciphertextBuilder.append(ciphertext[j]);
        }
        return result = ciphertext.toString();
    }

    public static void main(String[] args)
    {
        System.out.println(enciphing("b",6)); // здесь я тестирую  input
    }
}



Автор: Reaver 24.12.2009, 09:18
Первое что бросается в глаза, эта строка:
Код

input.toUpperCase(); 


Правильно написать 
Код

input = input.toUpperCase(); 

Метод String.toUpperCase() возвращает новую строку с преобразованным регистром, а не изменяет исходную.

Только после этого изменения программа начинает вылетать с ошибкой.
Да и решение слишком усложнено, вот так гораздо лучше, правда не учтена обработка пробелов:

Код

public class CeasarCipher {

    private static final String alphabetStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    private static final int alphabetLen = alphabetStr.length();

    public static String enciphing(String input, int shift) throws IllegalArgumentException{
        input = input.toUpperCase();
        char[] result = new char[input.length()];

        for (int i = 0; i < input.length(); i++) {
            int idx = alphabetStr.indexOf(input.charAt(i));
            if (idx == -1) {
                throw new IllegalArgumentException("Недопустимые символы в строке");
            }
            idx = (idx + shift) % alphabetLen;
            while (idx < 0) {
                idx += alphabetLen;
            }
            result[i] = alphabetStr.charAt(idx);
        }

        return new String(result);
    }
}

Автор: Qawra 24.12.2009, 12:56
Спасибо !
Я попыталась пристроить удаление пробелов вместо Exception используя continue label .
Но пока ничего не удаляется 
Код

 
       public static String enciphing(String input, int shift)  {
        int index;
        input = input.toUpperCase();
        char[] result = new char[input.length()];

      nextLabel:
        for (int i = 0; i < input.length(); i++) {    
            if (input.charAt(i) < 'A' || input.charAt(i) > 'Z')
            {
                continue nextLabel;
            } else 
                index = alphabetStr.indexOf(input.charAt(i));
           
                index = (index + shift) % alphabetLen;
            
            while (index < 0) {
                index += alphabetLen;
            }
            result[i] = alphabetStr.charAt(index);
        }

        return new String(result);
    }

Автор: Reaver 24.12.2009, 14:42
В данном случае можно добавить пробел в алфавит, либо просто пропускать символы, не входящие в алфавит:
 
Код

    public static String enciphing(String input, int shift){
        input = input.toUpperCase();
        char[] result = new char[input.length()];

        for (int i = 0; i < input.length(); i++) {
            int index = alphabetStr.indexOf(input.charAt(i));
            if (index != -1) {
                index = (index + shift) % alphabetLen;
                while (index < 0) {
                    index += alphabetLen;
                }
                result[i] = alphabetStr.charAt(index);
            }
        }

        return new String(result);
    }

Автор: Qawra 24.12.2009, 15:43
Я вынесла эту операцию в отдельный метод что бы не мучиться ,
буду вызывать её из enciphing и deciphing методов.

Я думаю что для того что-бы расшифровать то что мы зашифровали нам надо просто поменять + на - 
в строчке
Код

index = (index + shift) % alphabetLen;

Или этого недостаточно ?

Что-то я упустила в шифровании ..Компелируется , но результат выдаёт не тот который должен быть 
Код

 public static String enciphing(String input, int shift)  {
        int index;
        trimString(input);
        char[] result = new char[input.length()];
       for (int i = 0; i < input.length(); i++) {
        index = alphabetStr.indexOf(input.charAt(i));

                index = (index + shift) % alphabetLen;

            while (index < 0) {
                index += alphabetLen;
            }
            result[i] = alphabetStr.charAt(index);
        }
        return new String(result);
    }

на строчку 
Код

System.out.println(CeasarCipher2.enciphing("Piramida  heopsa", 4));

выдаёт "TDDDDDDDDDDDDDDD"
это он даже не заикается ... это он только первую букву правильно шифрует smile
trimString работает правильно , все пробелы удаляет


Я попробовала написать simple substitution алгоритм 
Код

public class SimpleSubstitutionCipher {
  
    public static final char[] alphabet = {'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 static String trimString(String input) {
        input = input.toUpperCase();
        input.trim();// removes empty spaces from start and end of the string

        int c = 0;
        char[] inputArray = new char[input.length()];
        nextLabel:
        for (int i = 0; i < input.length(); i++) {
            // пробелы почему-то не удаляются
            if (input.charAt(i) < 'A' || input.charAt(i) > 'Z') {
                continue nextLabel;
            } else {
                inputArray[c] = input.charAt(i);
            }
            c++;
        }
            String inputTemp = new String(inputArray);
            return input=inputTemp;
    }
    
    public static String encipingSubstitution(String input ,String key)
    {      
        int index;
        trimString(input);
        char [] keyArray= new char[26];
        char [] result=new char [input.length()];
        
        keyArray=key.toCharArray();//convert to char array
        
        for(int i=0; i<input.length(); i++)
        {
            index = alphabet.indexOf(input.charAt(i));
            
            result[i] = keyArray[index];
            
        }
                
      return new String(result);
    }
}

Он у меня получился каким-то подозрительно простым ,
И строчка 
Код

index = alphabet.indexOf(input.charAt(i));

 компайлеру не понравилась.
Говорит что не может найти метод indexOf 

 key для этого алгоритма я запрашиваю у пользователя как string , затем буквы из него (без повторов) переписываю в keyArray и добиваю его до размера английского алфавита с помощью этого самого алфавита 
Смотрится правда  достаточно запутано :
Код

public static char[] setKey(String key) {

        char[] keyTemp = key.toCharArray();//convert to char array

        Set notRepeatedSet = new TreeSet();
        for (char element : keyTemp) {
            notRepeatedSet.add(element);
        }

        Character [] uniq = (Character[]) notRepeatedSet.toArray(new
Character[notRepeatedSet.size()]);
        int c=0;
        for (int i=0; i<uniq.length; i++)
        {
            keyArray[i]=uniq[i]; // puts unigue letters from key to front of the keyArray
            c++;
        }

        for ( int j=c+1; j<26; j++) // we need to fill empty positions of keyArray with letters
        {
       alreadyThere:
            for(int x=0; x<26; x++) // goes through alphabet array
            {

                for (int y=0; y<c ;y++)//goes through array with unigue letters from key
                {
                   if(uniq[y]==alphabet[x]) //if letter already in the keyArray
                   {
                     continue alreadyThere; //goes for next letter of alphabete
                   }else keyArray[j]=alphabet[x]; // store letter into key array
                }
            }
        }
        return keyArray;
    }

не знаю будет ли работать потому что строчка 
Код

index = alphabet.indexOf(input.charAt(i));
 
в самом алгоритме пока не скомпелировалась по непонятной причине

Автор: Reaver 24.12.2009, 19:29
Цитата(Qawra @  24.12.2009,  13:43 Найти цитируемый пост)
Я думаю что для того что-бы расшифровать то что мы зашифровали нам надо просто поменять + на - в строчке
index = (index + shift) % alphabetLen;
Или этого недостаточно ?


В принципе, все правильно, но функцию дешифрования переписывать не надо. Можно просто написать таким образом:
Код

public static String deciphing(String input, int shift){
  return enciphing(input, -shift);
}


Во вторых, Вы повторяете те же самые ошибки, что и в начале. Метод trim() возвращает новую строку, а не изменяет старую, то же самое и с вашим методом trimString(String input). Так же, метод trim() удаляет пробелы только из начала и конца строки.
Для удаления всех пробелов не обязательно писать свою функцию, можно воспользоваться функцией String.replaceAll(" ", "");

Цитата(Qawra @  24.12.2009,  13:43 Найти цитируемый пост)
И строчка
index = alphabet.indexOf(input.charAt(i));
компайлеру не понравилась.Говорит что не может найти метод indexOf 


Первый мой пример компилировался без проблем? Если нет, то какую версию jdk Вы используете?

Во втором примере я немного ошибся. Вот готовый вариант кода, который просто пропускает символы. неиспользуемые в алфавите:
Код

public static String enciphing(String input, int shift)
            throws IllegalArgumentException {
        input = input.toUpperCase();
        
        char[] result = new char[input.length()];
        for (int i = 0; i < input.length(); i++) {
            int index = alphabetStr.indexOf(input.charAt(i));
            if (index != -1) {
                index = (index + shift) % alphabetLen;
                while (index < 0) {
                    index += alphabetLen;
                }
                result[i] = alphabetStr.charAt(index);
            } else {
                result[i] = ' ';
                System.out.println(input.charAt(i));
            }
        }
        return new String(result).replaceAll(" ", "");
    }


Автор: Qawra 24.12.2009, 19:50
Ошибку с trim() и trimString(String input) я исправила .

NetBeans 6.7.1 у меня установлен , но я в нём только начинающий пока программист smile
Могу что-нибудь перепутать .
Здесь выделена эта строчка, в первом классе она скомпелировалась без проблем 
Код

public class SimpleSubstitutionCipher {

    public static char[] keyArray = new char[26];
    public static final char[] alphabet = {'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 static String trimString(String input) {
        input = input.toUpperCase();
        input=input.trim();// removes empty spaces from start and end of the string

        int c = 0;
        char[] inputArray = new char[input.length()];
        nextLabel:
        for (int i = 0; i < input.length(); i++) {
            // пробелы почему-то не удаляются
            if (input.charAt(i) < 'A' || input.charAt(i) > 'Z') {
                continue nextLabel;
            } else {
                inputArray[c] = input.charAt(i);
            }
            c++;
        }
        String inputTemp = new String(inputArray);
        return input = inputTemp;
    }

    public static char[] setKey(String key) {

        char[] keyTemp = key.toCharArray();//convert to char array

        Set notRepeatedSet = new TreeSet();
        for (char element : keyTemp) {
            notRepeatedSet.add(element);
        }

        Character [] uniq = (Character[]) notRepeatedSet.toArray(new
Character[notRepeatedSet.size()]);
        int c=0;
        for (int i=0; i<uniq.length; i++)
        {
            keyArray[i]=uniq[i]; // puts unigue letters from key to front of the keyArray
            c++;
        }

        for ( int j=c+1; j<26; j++) // we need to fill empty positions of keyArray with letters
        {
       alreadyThere:
            for(int x=0; x<26; x++) // goes through alphabet array
            {

                for (int y=0; y<c ;y++)//goes through array with unigue letters from key
                {
                   if(uniq[y]==alphabet[x])//if letter already in the keyArray
                   {
                     continue alreadyThere; //goes for next letter of alphabete
                   }else keyArray[j]=alphabet[x]; // store letter into key array
                }
            }
        }
        return keyArray;
    }

    public static String encipingSubstitution(String input, String key) {
        int index;
        trimString(input);
        keyArray = setKey(key);

        char[] result = new char[input.length()];

        for (int i = 0; i < input.length(); i++) {
            index = alphabet.indexOf(input.charAt(i));

            result[i] = keyArray[index];
        }
        return new String(result);
    }
// uses the same key as encipingSubstitution method - keyArray which was already created
    public static String decipingSubstitution(String input) {

        return result;
    }

    public static void main(String[] args)
    {

    }
}

Автор: Reaver 24.12.2009, 20:14
У вас переменная alphabet имеет тип char[], а обращаетесь к ней как к типу String.

Автор: Qawra 24.12.2009, 23:13
Да , так оно и оказалось .Я уже переделала её в String  smile

Делаю сейчас  setKey для шифрования с субституцией .
Удаляются из  String   пробелы и дубликаты букв . То что остаётся становиться началом нового алфавита размером в 26 букв. Пустые места заполняются английским алфавитом начиная с буквы A.

Код

 public static char[] setKey(String key) {
        key=trimString(key);
        char[] keyTemp = key.toCharArray();//convert String to char array

        Set notRepeatedSet = new TreeSet();
        for (char element : keyTemp) {
            notRepeatedSet.add(element);
        }

        Character [] uniq = (Character[]) notRepeatedSet.toArray(new
Character[notRepeatedSet.size()]);
        int c=0;
        for (int i=0; i<uniq.length; i++)
        {
            keyArray[i]=uniq[i]; // puts unigue letters from key to front of the keyArray
            c++;
        }

        for ( int j=c; j<26; j++) // we need to fill empty positions of keyArray with letters
        {
       alreadyThere:
            for(int x=0; x<26; x++) // goes through alphabet array
            {
                for (int y=0; y<c ;y++)//goes through array with unigue letters from key
                {
                   if(uniq[y]==alphabet[x])//if letter already in the keyArray
                   {
                     continue alreadyThere; //goes for next letter of alphabete
                   }else keyArray[c]=alphabet[x]; // store letter into key array
                }
            }
        }
        return keyArray;
    }


Непонятно почему после удаления пробелов и дубликатов буквы оказываются в алфавитном порядке . А вместо английского алфавита  впечатывается буква Z .
Например :
Код

System.out.println(SimpleSubstitutionCipher.setKey(" ttuutoonneerrmmv "));


печатает EMNORTUVZ

Мне кажется что inner loops надо переставить местами чтобы английский алфавит допечатывать в key.
Ну а  порядок букв видимо результат использования TreeSet ...?





Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)