计算字符串中的字母序列 - C++
Count sequences of letters in a string - C++
我正在研究一个简单的替代密码解码器。我正在使用频率分析来解密密文。只看独特字母的频率是不够的。我需要查看 2 个字母序列(可能是 3 个字母序列)的出现次数。
我计算每个字母出现次数的代码如下
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 字母序列计数器,你有什么想法可以帮助我编写这个代码吗?
谢谢!
编辑:举个例子
鉴于 AZAZ RTYU JKLM 我希望我的程序输出:
AZ : 2
ZA : 1
ZR : 1
RT : 1
...
你现在正在做的是计数排序。
如果您考虑多个数字,基数排序对您来说是一个可行的选择。
你应该用两个字母创建一个 "composite letter"。
由于 C、C++ 中的字母是数字,您可以将 2 个字母中的每一个转换为数字(字符已经是数字),然后用两个数字创建一个数字。例如int C=输入字符串[i]+256*输入字符串[i+1]。
上面假设字符串是 char 并且 chars 在 0 到 255 之间(比有符号更好)。
给你(基于的想法):
#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();
}
像下面这样的东西就可以了,尽管你必须做一些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
我正在研究一个简单的替代密码解码器。我正在使用频率分析来解密密文。只看独特字母的频率是不够的。我需要查看 2 个字母序列(可能是 3 个字母序列)的出现次数。
我计算每个字母出现次数的代码如下
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 字母序列计数器,你有什么想法可以帮助我编写这个代码吗?
谢谢!
编辑:举个例子 鉴于 AZAZ RTYU JKLM 我希望我的程序输出:
AZ : 2
ZA : 1
ZR : 1
RT : 1
...
你现在正在做的是计数排序。 如果您考虑多个数字,基数排序对您来说是一个可行的选择。
你应该用两个字母创建一个 "composite letter"。 由于 C、C++ 中的字母是数字,您可以将 2 个字母中的每一个转换为数字(字符已经是数字),然后用两个数字创建一个数字。例如int C=输入字符串[i]+256*输入字符串[i+1]。 上面假设字符串是 char 并且 chars 在 0 到 255 之间(比有符号更好)。
给你(基于
#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();
}
像下面这样的东西就可以了,尽管你必须做一些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