【问题标题】:String encoding issue?字符串编码问题?
【发布时间】:2018-03-31 17:36:21
【问题描述】:

我开发了一个convertBase 函数,它能够将值转换为不同的基数并返回。

string convertBase(string value, int fBase, int tBase) {
    string  charset =  "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+/",
            fromRange = charset.substr(0, fBase),
            toRange = charset.substr(0, tBase),
            cc(value.rbegin(), value.rend()),
            res = "";
    unsigned long   int dec = 0;
                    int index = 0;

    for(char& digit : cc) {
        if (charset.find(digit) == std::string::npos) return "";
        dec += fromRange.find(digit) * pow(fBase, index);
        index++;
    }
    while (dec > 0) {
        res = toRange[dec % tBase] + res;
        dec = (dec - (dec % tBase)) / tBase;
    }; return res;
}

代码在编码像"Test" 这样的简单字符串并再次返回时工作,但是在编码像"Test1234567" 这样的长字符串时遇到问题,因为它被编码为"33333333333333333333333333333333",这似乎是绝对错误的!

为什么会发生这种情况以及如何解决这个问题?

【问题讨论】:

  • 首先,如果您使用 C++ 编程,请不要添加任何不相关的语言标签。其次,这是learn how to debug your programs的最佳时机。
  • fBasetBase 有哪些值? unsigned long 是否足够大以供您计算? (我希望:没有)。您使用的是 pow 的哪个重载 - 没有声明在 cplusplus.com/reference/cmath/pow 处返回整数类型
  • 好吧听起来合法,但有什么替代方法可以代替“unsigned long”? @milbrandt
  • 您可能会使用一些大型 int 库,如 stackoverflow.com/questions/1055661/bigint-bigbit-library 中引用的。你的算法是否适用于long double precisssion?
  • 取模不是问题。 a % b = a - floor(a/b)*b 也适用于十进制类型。

标签: c++ arrays string math base


【解决方案1】:

long int 通常大小为 32 位或 64 位,具体取决于您使用的 CPU 架构,但它甚至可以有其他大小。您正在向dec 添加越来越大的数字。在某些时候,数字变得比long int 可以容纳的更大,然后您的程序就会崩溃。

如果您需要处理任意大的输入,则需要使用不同的方法。如果可以,请使用“bignum”或“bigint”库,例如 GMP

【讨论】:

  • 感谢您的快速回答。但我无法真正理解你的想法。 “在处理 cc 时,您必须找到某种方法将字符添加到 res ”是什么意思?你介意分享一些代码吗? :)
  • 我确实介意,因为如果您尝试使用我给您的提示自己找到解决方案,这将比我只是将解决方案交给您 :) 无论如何,您已经写了大部分的代码。只是您要等到处理完所有输入后再开始写入输出。相反,每当您处理了一个输入字符时,请尝试查看dec 是否足够大,以便您可以编写一些输出,然后再编写该输出。这应该类似于将整个 while-loop 移动到 for-loop 中,但稍微改变了条件,并进行了一些额外的记账。
  • 首先,我非常感谢您提供的有用提示和 cmets,但我必须说实话:我确信您的回答在内容上是完全正确且正确的,但我必须诚实地说这个答案并没有带给我太多。我更像是“尝试”类型而不是“理论”类型。而且由于我已经连续 2 天坐在这个 en / decode 功能上,今天刚刚绝望地转向 SO,因此也对你 & 仍然不知道如何最终解决我真的很接近的问题放弃。 “试试看 dec 是否很大……那个输出”。不知道该怎么做!
  • 您缺少declaration of charset, ...function call! ^@G.Sliepen 所以你的代码看起来让我们称之为 - 销毁:) 编辑: 你犯了一个错误:你必须使用 value 而不是相反的值 cc迭代。请编辑。
  • 好吧,太晚了,明天我会尝试发布更好的代码。但我认为使用颠倒的值仍然是正确的。
【解决方案2】:

开始调试时,大问题变得显而易见。让我们先拨打convertBase("Test",3, 4)

string  charset =  "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+/",
        fromRange = charset.substr(0, fBase),
        toRange = charset.substr(0, tBase),

substr 从开始 (0) 个 xBase 字符开始复制。这将导致示例案例fromRange = "012"toRange="0123"

for(char& digit : cc) {
    if (charset.find(digit) == std::string::npos) return "";
    dec += fromRange.find(digit) * pow(fBase, index);

charsetdigit的测试会成功,所以不会执行return。

但是已经在第一次迭代中,当digit=='t',在fromRange.find(digit) 中找不到它并且std::string::npos 被乘以一些东西。但不仅 t 会映射到这个值,charset 中但不是fromRange 中的任何字符都将获得相同的值。这是不可逆的,没有双射!

…… 这导致得出的结论是,该算法不会独立于任何整数值限制而工作。

【讨论】:

  • 在您的问题和代码中,参数fbasetbase 没有任何限制。然后请提供您对方法的调用或至少说明任何限制。我不喜欢猜测你隐含的假设。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-01-08
  • 1970-01-01
  • 2012-02-22
  • 2019-11-17
  • 1970-01-01
  • 2020-04-04
  • 1970-01-01
相关资源
最近更新 更多