Шифр Цезаря не возвращает правильный ключ

Таким образом, моя программа-дешифратор, похоже, не может найти ключ и реализовать его самостоятельно. Я заметил, что если я изменю ключ на равный -5, который является правильным ключом, он правильно распечатает расшифрованный текст. Однако я не могу понять, как заставить программу понять это самостоятельно, не заставляя меня вводить ее вручную. Любая помощь будет принята с благодарностью! Благодарю вас!

rotUtils.h

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>

#include "rotUtils.h"

int rotate(int c, int n){
  if (n == 0) return c;
  int nRot = abs(n) % (RANGECHAR + 1);
  if(n > 0)
    return rotatePlus(c + nRot);
  else
    return rotateMinus(c - nRot);
}

int rotatePlus(int sum){
  int diff = sum - MAXCHAR;
  if (sum > MAXCHAR) sum = MINCHAR + diff - 1;
  return sum;
}

int rotateMinus(int sum){
  int diff = MINCHAR - sum;
  if (sum < MINCHAR) sum = MAXCHAR - diff + 1;
  return sum;
}

decrypt.cpp

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "rotUtils.h"

bool solved( char decodearr[], char dictarr[][30], int size1, int size2){

    char* compared;
    bool result = false;

    for(int j = 0; j < size2; j++){

    compared = strstr( decodearr, dictarr[j]);

    }
    if( compared != '\0'){

     result = true;

         }
    return result;

}

int decode( char codearr[], char dictarr[][30], int size1, int size2)
    {
    bool solution = false;
    int key = -50; This is where I had to change it to -5 to solve 

    char decodearr[10000];
    while(solution == false && key < 51)
    {
     for( int i = 0; i < size1; i++)
        {
        if(!isspace(codearr[i]))
         {
          decodearr[i] = rotate(codearr[i], key);
          }
        else
          decodearr[i] = codearr[i];


    }

    solution = solved( decodearr, dictarr, size1, size2);
    if( solution == false)
     {
      key++;
      }
    }

  for( int j = 0; j < size1; j++)
    {
    codearr[j] = decodearr[j];
    }
  return key;
}

    int main( int argc, char* argv[])
    {
    char* file = argv[1];
    char* dictionary = argv[2];
    char code[10000];
    char dict[30000][30];
    FILE* codeFile;
    codeFile = fopen(file, "r");
    int i = 0;
    int j = 0;
    int key;
    FILE* dictFile;
    dictFile = fopen(dictionary, "r");

    while(!feof(codeFile))
    {
    code[i] = fgetc(codeFile);
    i++;
    }

    code[ i ]= '\0';
    fclose(codeFile);

    while(!feof(dictFile))
    {
    fscanf(dictFile, "%s", dict[j]);
    j++;
    }

    key = decode(code, dict, i, j);
    fclose(dictFile);

        for(int k = 0; k < i; k++)
        {
        printf("%c", code[k]);
        }

    printf( "\nThe key is: %d\n", key);

    return 0;
}

person JBo    schedule 30.03.2015    source источник
comment
На данный момент вы проверяете только один ключ, -50. Вы должны проверять различные ключи до тех пор, пока хороший процент слов в декодированном сообщении не окажется словами в словаре. Это означает, что вам нужен поиск по словарю, возможно, бинарный поиск. Атака грубой силой просто перепробует все возможные ключи, которых не так много в шифре Цезаря. Если вы хотите, вы можете добавить некоторые эвристики, например, предположив, что наиболее часто встречающаяся кодовая буква — это «е», и сначала попробовать такие ключи.   -  person M Oehm    schedule 30.03.2015
comment
@MOehm Я добавил файл заголовка с функцией поворота, если это поможет. И я использую файл smallDictionary в argv[2], который читается.   -  person JBo    schedule 30.03.2015
comment
Да, я видел это. У вас есть функция, которая сообщает вам, есть ли слово в словаре? (Я предполагаю, что слова в dict отсортированы и можно использовать бинарный поиск. Или уже реализован smallDictionary?)   -  person M Oehm    schedule 30.03.2015
comment
@MOehm Слова в словаре отсортированы, но у меня пока нет функции, чтобы определить, является ли это словом. Буду ли я использовать strstr снова, чтобы сравнить его со словом в словаре?   -  person JBo    schedule 30.03.2015
comment
Вы можете использовать strstr, но это будет медленно. Вы должны найти слова (т.е. отрезки букв без знаков препинания) в декодированном тексте, а затем выполнить бинарный поиск. Бинарный поиск — очень простой алгоритм; вы должны быть в состоянии найти ресурсы в Интернете.   -  person M Oehm    schedule 30.03.2015
comment
А, теперь я увидел, что вы уже сравниваете расшифрованный текст и диктовку. Посмотрите на комментарий Джии. Но даже если вы это исправите, ваша логика неверна: вам не нужно проверять, есть ли в сообщении каждое слово из словаря; вы должны проверить, сколько слов в сообщении есть в словаре.   -  person M Oehm    schedule 30.03.2015
comment
да, он прав, поэтому я попросил вас распечатать все решения и не останавливаться на первом, которое вы получите, чтобы вы видели, что происходит. Позже вы можете вместо этого изменить result=true на счетчик, после того, как ваша проверка словаря проверит счетчик по сравнению со значением, которое вам нравится для правильного результата (например, 25 слов из 100), я бы все же предпочел вернуть набор возможных результатов, чем пытаясь выбрать один, список помогает больше, когда вы тестируете миллионы возможностей. Но это зависит от вас.   -  person gia    schedule 30.03.2015
comment
@gia Как я могу распечатать эти решения, которые я получаю в основной функции?   -  person JBo    schedule 30.03.2015
comment
ваша программа кажется однопоточной, вы можете без опасений печатать что угодно где угодно :), если вы все равно хотите сохранить результаты, быстрый способ - создать глобальный массив и сохранить его там, вы можете получить к нему доступ из любой части вашего кода, если вы предпочитаете лучшие практики, вы можете использовать возвращаемое значение, возвращать массив со всеми возможными ключами вместо одного ключа. Для миллионов тестов я предлагаю вам вместо этого писать в файл, который вы создаете (например, в файл журнала), или сохранять в базу данных (дополнительная работа).   -  person gia    schedule 30.03.2015


Ответы (1)


Solved() вернет true только в том случае, если в настоящее время есть совпадение с последним словом словаря, вам нужно переместить эту проверку внутрь. Вы можете печатать на экране всякий раз, когда найдете ключ, который соответствует вашему словарю, и/или сохранить список возможных ключей, а затем распечатать после того, как вы закончите с ними всеми, прямо сейчас вы выйдете, как только найдете какое-либо совпадение, даже если это была просто удача.

person gia    schedule 30.03.2015
comment
Что вы имеете в виду под необходимостью переместить этот чек внутрь? - person JBo; 30.03.2015
comment
При решении(), if(compared...) переместите его внутрь for() перед ним. Прямо сейчас он находится за пределами for(), поэтому он выполняется только после того, как вы закончите зацикливать все свои словарные слова. - person gia; 30.03.2015