2015-01-23 2 views
0

Я работаю над простым декодером-шифратором. Я использую частотный анализ для расшифровки зашифрованного текста. Просто смотреть на частоту уникальной буквы недостаточно. Мне нужно посмотреть на появление 2-буквенных последовательностей (возможно, 3-буквенных последовательностей).Считайте последовательности букв в строке - C++

Мой код для подсчета вхождений каждой буквы ниже

int counterRaw[256][2] = {0}; 
    for(int i = 0; i <inputString.length(); i++) 
     counterRaw[inputString[i]][1]++; 

int counterLetter[26][2] = {0}; 
    for(int i = 0 ; i<26 ; i++){ 
     counterLetter[i][0] = 'A'+i; 
     counterLetter[i][1] = counterRaw['A'+i][1]; 

Как вы можете видеть очень простой, но эффективный!

Но я не знаю, как добиться 2-буквенного счетчика последовательности, есть ли у вас какие-либо идеи, которые могли бы помочь мне закодировать это?

Спасибо!

EDIT: В качестве примера Учитывая Азаза RTYU JKLM Я хочу, чтобы моя программа для вывода:

AZ : 2 
ZA : 1 
ZR : 1 
RT : 1 
... 
+0

так дано '1a2bc3de4', граф будет' 2', потому что есть '' bc' и de' для двух последовательностей букв? –

+0

Возможно, самое простое решение: используйте std :: map. –

+0

Если вам нужны только две буквы, массив из вхождений int [26] [26]; было бы достаточно. – maja

ответ

0

Что-то вроде следующего будет делать трюк, хотя вы должны сделать некоторые jiggery pokery, чтобы сделать его удовлетворить ваши собственные потребности.

#include <iostream> 
#include <map> 
#include <string> 

int main() 
{ 
    std::string message("some string that you will probably get from some encrypted file"); 
    std::map<std::string,int> occurences; 

    std::string seq(" "); 
    for(int i = 1; i < message.length() - 1; i++) 
    { 
     seq[0] = message[i-1]; 
     seq[1] = message[i]; 

     //ignore spaces 
     if (seq.compare(0,1, " ") && seq.compare(1,1, " ")) 
     { 
      occurences[seq]++; 
     } 
    } 

    //let's have a look ... 
    for(auto iter = occurences.begin(); iter != occurences.end(); ++iter) 
    { 
     std::cout << iter->first << " " << iter->second << "\n"; 
    } 
    return 0; 
} 

выход:

ab 1 
at 1 
ba 1 
bl 1 
cr 1 
ed 1 
en 1 
et 1 
fi 1 
fr 1 
ge 1 
ha 1 
il 2 
in 1 
ll 1 
ly 1 
me 2 
nc 1 
ng 1 
ob 1 
om 3 
ou 1 
pr 1 
pt 1 
ri 1 
ro 2 
ry 1 
so 2 
st 1 
te 1 
th 1 
tr 1 
wi 1 
yo 1 
yp 1 
+0

Используйте только std :: string в качестве ключа карты, если это необходимо. Потому что это ** медленно **. – Axalo

+0

Очень приятно!Тем не менее, пространство между двумя словами делает неправильный результат («некоторая строка» -> «es»). Но спасибо, это хороший выстрел! – Bikemat

+0

@Bikemat, я не буду следовать за вами здесь, я не вижу «es» в выпуске, который я дал:/ – HexedAgain

0

То, что вы делаете прямо сейчас счетные рода. Род-сортировка была бы жизнеспособным вариантом для вас, если вы принимаете несколько цифр.

1

Вы должны создать «составную букву» из двух букв. Как буквы в C, C++ - это числа, вы можете просто преобразовать каждую из двух букв в число (символы уже являются числами) и создать число с двумя числами. например int C = inputString [i] + 256 * inputString [i + 1]. Вышеприведенное с предположением, что строки имеют символ и символы от 0 до 255 (лучше, чем подписанные).

+0

Это может быть хорошим способом решения проблемы. Но я боюсь, что не смогу получить пары писем, которые использовались для сборки моего номера. Например: 'A' + 'K' = 60 + 70 = 'F' + 'F' = 65 + 65 = 130. Возможно, массив [] [3] (строки = все возможные пары, первая буква столбца - вторая буква - появление) ... – Bikemat

0

Здесь вы идете (основано на идее user3723779):

#define MAKEWORD(a, b) (((a) << 8) | (b)) 

std::string noSpaces(std::string s) 
{ 
    int pos; 
    while((pos = s.find(' ')) != std::string::npos) 
    { 
     s.erase(pos, 1); 
    } 
    return s; 
} 

std::map<short, int> seqDet2(const std::string &s) 
{ 
    int length = s.length(); 
    if(length == 0) return std::map<short, int>(); 

    // assert(sizeof(char) == 1); 
    std::vector<short> v; 

    for(int i = 0; i < length - 1; ++i) 
    { 
     v.push_back(MAKEWORD(s[i], s[i + 1])); 
    } 

    std::map<short, int> occ; 
    for(auto x: v) 
    { 
     occ[x]++; 
    } 

    return occ; 
} 

int main() 
{ 
    std::string s = "AZAZRTYUI AZTWI"; 
    auto occ = seqDet2(noSpaces(s)); 

    for(auto x: occ) 
    { 
     unsigned char b = (unsigned char)x.first; 
     unsigned char a = (unsigned char)(x.first >> 8); 
     printf("%c%c - %d\n", a, b, x.second); 
    } 

    getchar(); 
} 
+0

Ну, я думаю, этот код работает для таких же последовательностей букв, как AA ZZZ EE ... (посмотрите на мое редактирование: p) Но я получу идею;) – Bikemat

+0

@Bikemat отредактировал – Axalo

+0

Очень приятно! Тем не менее, если в тексте шифрования (как у меня) есть пробел между двумя словами, результат будет неправильным. Мне просто нужно это обработать. Но спасибо, это действительно полезно! – Bikemat

Смежные вопросы