在stl中是否有任何函数进行字符串转换,但是有一个长度参数?

时间:2013-07-11 23:27:45

标签: c++ stl

假设你有一个字符串:

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

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

int atoi_n(char *, int len);

我错过了什么? strtok\t替换为\0,我不想触及原始缓冲区。我发现很难相信没有atoiatof等实例采用长度参数,但我找不到任何内容。

任何人都知道我有什么东西不见了?我知道boost有一些标记符,但我想避免添加boost的依赖。

到目前为止看的评论我想澄清一下。让我们改变一下场景: char buffer [1024]; char * pStartPos; char * pEndPost; pStartPos = buffer + 5; pEndPos = buffer + 10;

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

2 个答案:

答案 0 :(得分:4)

如果你只想解析字符串的结尾(从\t之后的字符到结尾)你只需要传递指向第一个字符的指针来解析atoi ...

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

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

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

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

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

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


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


  

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

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

substr

答案 1 :(得分: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;

}