0

假设你有一个字符串:

std::string s = "ABCD\t1234";

我可以std::string::find用来获取 '\t' 字符的偏移量,但据我所知,没有具有以下签名的函数:

int atoi_n(char *, int len);

我错过了什么?strtok替换为\t\0我不想触摸原始缓冲区。我很难相信没有带长度参数的 , 等实例atoiatof但我找不到任何东西。

有人知道我是否缺少某些东西吗?我知道 boost 有一些标记器,但我想避免添加 boost 的依赖项。

到目前为止,我想澄清一下评论。让我们换个场景:char buffer[1024]; 字符 *pStartPos; 字符 *pEndPost; pStartPos = 缓冲区 + 5; pEndPos = 缓冲区 + 10;

假设您不能对 pStartPos 和 pEndPos 之外的内存做出任何假设。如何将 pStartPos 和 pEndPos 之间的字符转换为 int 而不添加 '\0' 到缓冲区或使用 substr 复制?

4

2 回答 2

4

如果您只想解析字符串的结尾(从后面的字符\t到结尾),您只需将指针传递给要解析的第一个字符atoi...

int n = atoi(s.c_str()+s.find('\t')+1);

(为简洁起见省略了错误检查 - 特别是,我们总是假设 a\t实际存在)

相反,如果您想从字符串的开头解析到\t您可以这样做

int n = atoi(s.c_str());

因为atoi无论如何都会停在第一个非数字字符处。

顺便说一句,您应该考虑使用更强大的解决方案来解析数字,例如strtolsscanfC++ 流 - 它们都可以以某种方式报告解析错误,而atoi只是返回0(这与来自解析的 0 无法区分字符串)。


顺便说一句,atoi无论如何,它都不在“STL”中——它只是 C 标准库的一部分。


我知道 atoi 不在 STL 中。我想知道 STL 中是否有类似的东西,您可以在其中指定要包含在转换中的最后一个字符。基本上我有一个缓冲区,它可能部分被垃圾填满。我知道可能的有效数据的开始和可能的有效数据的结束。我不想依靠空格来结束转换,我想明确说明“字段”的长度,因为它也可能不是 /0 终止的。

如果您确定垃圾不是以数字开头的,您可以按原样使用atoi// strtol-istringstream它们会在看到垃圾时自动停止。否则,使用该substr方法提取您需要的确切子字符串:

std::string mayContainGarbage="alcak123456amaclmò";
std::string onlyTheDigits=mayContainGarbage.substr(5, 6);
// now parse onlyTheDigits as you prefer
于 2013-07-11T23:32:28.643 回答
1

据我所知,没有这种开箱即用的功能,但实现起来应该不难。

例如:

template <typename ForwardIterator>
int range_to_int(ForwardIterator begin, ForwardIterator past_end) {

    if (begin != past_end) {

        bool negative = false;

        auto ch = *begin;
        if (ch == '-') {
            negative = true;
            ++begin;
        }
        else if (ch == '+')
            ++begin;

        if (begin != past_end) {

            int result = 0;

            do {
                auto ch = *begin;
                if (ch < '0' || ch > '9')
                    throw std::invalid_argument("Invalid digit.");
                result = result * 10 + (ch - '0');
                ++begin;
            } while (begin != past_end);

            if (negative)
                result = -result;

            return result;

        }

        throw std::invalid_argument("+ or - must be followed by at least one digit.");

    }

    throw std::invalid_argument("Empty range.");

}

你可以像这样使用它:

int main() {

    const char* buffer = "abc-123def";

    int i = range_to_int(buffer + 4, buffer + 7);
    assert(i == 123);

    i = range_to_int(buffer + 3, buffer + 7);
    assert(i == -123);

    try {
        i = range_to_int(buffer + 3, buffer + 8);
        assert(false);
    }
    catch (const std::exception& ex) {
        std::cout << ex.what() << std::endl;
    }

    try {
        i = range_to_int(buffer + 3, buffer + 4);
        assert(false);
    }
    catch (const std::exception& ex) {
        std::cout << ex.what() << std::endl;
    }

    try {
        i = range_to_int(buffer + 4, buffer + 4);
        assert(false);
    }
    catch (const std::exception& ex) {
        std::cout << ex.what() << std::endl;
    }

    // You can use it on std::string as well....

    const std::string str = buffer;

    i = range_to_int(str.begin() + 4, str.begin() + 7);
    assert(i == 123);

    // Etc...

    return EXIT_SUCCESS;

}
于 2013-07-13T01:47:50.820 回答