【问题标题】:Count sequences of letters in a string - C++计算字符串中的字母序列 - C++
【发布时间】:2015-01-23 19:54:08
【问题描述】:

我正在开发一个简单的替换密码解码器。我正在使用频率分析来解密密文。仅查看唯一字母的频率是不够的。我需要查看 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
...

【问题讨论】:

  • 所以给定1a2bc3de4,计数将是2,因为两个字母序列有bcde
  • 可能是最简单的解决方案:使用 std::map。
  • 如果你只需要2个字母,一个int出现的数组[26][26];就足够了。
  • 我很想在遍历字符串的字符时散列/检查键值。

标签: c++ encryption counter frequency-analysis


【解决方案1】:

您应该从两个字母创建一个“复合字母”。 由于 C、C++ 中的字母是数字,您只需将 2 个字母中的每一个都转换为数字(字符已经是数字),然后用两个数字创建一个数字。例如整数 C=inputString[i]+256*inputString[i+1]。 以上假设字符串是 char 且 chars 介于 0 到 255 之间(比有符号好)。

【讨论】:

  • 这可能是解决问题的好方法。但恐怕我将无法检索用于构建我的号码的字母对。例如 'A'+ 'K' = 60+70 = 'F'+'F' = 65 + 65 = 130。也许是一个数组 [][3] (行 = 所有可能的对,列第一个字母 - 第二个字母 - 出现) ...
【解决方案2】:

类似下面的方法可以解决问题,但您必须做一些棘手的事情才能使其适合您自己的需要。

#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

【讨论】:

  • 如果必须,仅使用 std::string 作为映射键。因为它
  • 非常好!尽管如此,两个单词之间的空格仍然使结果错误(“some string”->“es”)。但是谢谢,这是一个好镜头!
  • @Bikemat,我没有关注你,我在我给出的输出中没有看到“es”:/
  • @Alaxo,我同意这不是最快的实现,但它只是一个模型来传达这个想法......重构它并根据他/她自己的需要定制它取决于 Bikemat。跨度>
  • @HexedAgain 好吧,您的代码似乎忽略了空格: if (seq.compare(0,1, " ") && seq.compare(1,1, " ")) {occurrences[seq] ++;但是,如果是这种情况,您应该在 message("some string ...") 的输出中得到 - 例如 - “ES”,不是吗?不过谢谢你,我目前正在根据自己的需要调整它;)
【解决方案3】:

您现在正在做的是计数排序。 如果您考虑多个数字,基数排序对您来说是一个可行的选择。

【讨论】:

    【解决方案4】:

    给你(基于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();
    }
    

    【讨论】:

    • 好吧,我认为这段代码适用于相同字母序列,例如 AA ZZZ EE ...(看看我的编辑:p)但我明白了;)
    • 非常好!尽管如此,如果密文中的两个单词之间有空格(如我的),输出将是错误的。我只需要处理那个。不过谢谢,这真的很有帮助!
    • 我在您的示例中看不到任何空格。
    • 糟糕,我编辑了主题。我的密文被分组为 4 个字母的块以掩盖单词;)
    猜你喜欢
    • 1970-01-01
    • 2014-07-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多