在C ++中将vector <string>转换为unsigned char数组

时间:2017-04-18 06:17:45

标签: c++ arrays vector char type-conversion

我有一个包含一些值的字符串向量。这些值应该是十六进制字节,但是作为字符串存储在此向量中。     实际上是从文本文件中读取字节,如下所示:

文本文件的内容

<jpeg1>
0xFF,0xD8,0xFF,0xE0,0x00,0x10,0x4A,0x46,0x49,0x46,0x00,0x01,0x01,0x01,0x00,0x60
</jpeg1>

到目前为止,我的代码所做的是,它开始读取 {JPEG1} 标记之后的行,直到 {/ jpeg1} 标记然后使用逗号' ,'作为分隔符,它将字节存储到字符串向量中。

分割字符串后,此时的矢量会存储如下值:

vector<string> myString = {"0xFF", "0xD8", "0xFF", "0xE0", "0x00", "0x10", "0x4A", "0x46", "0x49", "0x46", "0x00", "0x01", "0x01", "0x01", "0x00", "0x60"};

        and if i print this i get the following:
            0: 0xFF
            1: 0xD8
            2: 0xFF
            3: 0xE0
            4: 0x00
            5: 0x10
            6: 0x4A
            7: 0x46
            8: 0x49
            9: 0x46

我想要的是,我想将这些字节存储在unsigned char数组中,这样每个元素都被视为HEX字节而不是字符串值。

最好像这样:

     unsigned char myHexArray[] = {0xFF,0xD8,0xFF,0xE0,0x00,0x10,0x4A,0x46,0x49,0x46,0x00,0x01,0x01,0x01,0x00,0x60};

        if i print this i get:
            0:  
            1: ╪
            2:  
            3: α
            4:
            5: 
            6: J
            7: F
            8: I
            9: F

解决!
感谢您的帮助,到目前为止“ranban282”解决方案对我有用,我也会尝试其他用户提供的解决方案。

4 个答案:

答案 0 :(得分:2)

我甚至不会经历std::vector<std::string>阶段,你不需要它,它没有充分的理由浪费了很多分配;只需将字符串解析为“在线”字节。

如果你的数据已经有istream,你可以直接解析它,虽然我对它的性能有很糟糕的体验。

// is is some derived class of std::istream
std::vector<unsigned char> ret;
while(is) {
    int val = 0;
    is>>std::hex>>val;
    if(!is) {
        break; // failed conversion; remember to clean up the stream
               // if you need it later!
    }
    ret.push_back(val);
    if(is.getc()!=',') break;
}

如果你把它放在一个字符串中 - 就像从XML文件中提取数据时经常发生的那样,你可以使用istringstream和上面的代码解析它(一个额外的字符串副本+通常很慢),或者使用例如直接从字符串解析它sscanf%i;说你的字符串在const char *sz

std::vector<unsigned char> ret;
for(; *sz; ++sz) {
    int read = 0;
    int val = 0;
    if(sscanf(sz, " %i %n", &val, &read)==0) break; // format error
    ret.push_back(val):
    sz += read;
    if(*sz && *sz != ',') break; // format error
} 
// now ret contains the decoded string

如果您确定字符串始终是十六进制的,那么无论0x前缀如何,并且该空格不存在strtol会更有效并且IMO更好用:

std::vector<unsigned char> ret;
for( ;*sz;++sz) {
    char *endp;
    long val = strtol(sz, &endp, 16);
    if(endp==sz) break; // format error
    sz = endp;
    ret.push_back(val);
    if(*sz && *sz!=',') break; // format error
}

如果C ++ 17可用,您可以使用std::from_chars而不是strtol来删除区域设置废话,这可能会破坏您的解析功能(尽管这对于浮点解析更为典型)放慢速度没有任何理由。

OTOH,如果性能很关键,但from_chars不可用(或者如果它可用,但你测得它很慢),手动滚动整个解析器可能是有利的。

auto conv_digit = [](char c) -> int {
    if(c>='0' && c<='9') return c-'0';
    // notice: technically not guaranteed to work;
    // in practice it'll work on anything that doesn't use EBCDIC
    if(c>='A' && c<='F') return c-'A'+10;
    if(c>='a' && c<='f') return c-'a'+10;
    return -1;
};
std::vector<unsigned char> ret;
for(; *sz; ++sz) {
    while(*sz == ' ') ++sz;
    if(*sz!='0' || sz[1]!='x' || sz[1]!='X') break; // format error
    sz+=2;
    int val = 0;
    int digit = -1;
    const char *sz_before = sz;
    while((digit = conv_digit(*sz)) >= 0) {
        val=val*16+digit; // or, if you prefer: val = val<<4 | digit;
        ++sz;
    }
    if(sz==sz_before) break; // format error
    ret.push_back(val);
    while(*sz == ' ') ++sz;
    if(*sz && *sz!=',') break; // format error
}

答案 1 :(得分:1)

如果您正在使用C ++ 11,则可以使用stoi功能。

vector<string> myString = {"0xFF", "0xD8", "0xFF", "0xE0", "0x00", "0x10", "0x4A", "0x46", "0x49", "0x46", "0x00", "0x01", "0x01", "0x01", "0x00", "0x60"};
    unsigned char* myHexArray=new unsigned char[myString.size()];
    for (unsigned  i=0;i<myString.size();i++)
    {
            myHexArray[i]=stoi(myString[i],NULL,0);
    }
    for (unsigned i=0;i<myString.size();i++)
    {
            cout<<myHexArray[i]<<endl;
    }

函数stoi()由C ++ 11引入。为了使用gcc进行编译,您应该使用标志-std = c ++ 11进行编译。

如果您使用旧版本的c ++,可以使用strtol代替stoi。请注意,您需要先将字符串转换为字符数组。

myHexArray[i]=strtol(myString[i].c_str(),NULL,0);

答案 2 :(得分:1)

您可以对每个值使用std::stoul,并使用另一个std::vector构建阵列,如下所示:

std::vector<std::string> vs {"0xFF", "0xD8", "0xFF" ...};

std::vector<unsigned char> vc;
vc.reserve(vs.size());

for(auto const& s: vs)
    vc.push_back((unsigned char) std::stoul(s, 0, 0));

现在您可以使用以下命令访问数组:

vc.data(); // <-- pointer to unsigned char array

答案 3 :(得分:0)

这是一个完整的解决方案,包括测试和基本解析器(为简单起见,它假设xml标签位于各自的行上)。

#include <string>
#include <sstream>
#include <regex>
#include <iostream>
#include <iomanip>
#include <iterator>

const char test_data[] =
R"__(<jpeg1>
0xFF,0xD8,0xFF,0xE0,0x00,0x10,0x4A,0x46,0x49,0x46,0x00,0x01,0x01,0x01,0x00,0x60,
0x12,0x34,0x56,0x78,0x9a,0xbc,0xde,0xf0
</jpeg1>)__";


struct Jpeg
{
    std::string name;
    std::vector<std::uint8_t> data;
};

std::ostream& operator<<(std::ostream& os, const Jpeg& j)
{
    os << j.name << " : ";
    const char* sep = " ";
    os << '[';
    for (auto b : j.data) {
        os << sep << std::hex << std::setfill('0') << std::setw(2) << std::uint32_t(b);
        sep = ", ";
    }
    return os << " ]";

}

template<class OutIter>
OutIter read_bytes(OutIter dest, std::istream& source)
{
    std::string buffer;
    while (std::getline(source, buffer, ','))
    {
        *dest++ = static_cast<std::uint8_t>(std::stoul(buffer, 0, 16));
    }
    return dest;
}

Jpeg read_jpeg(std::istream& is)
{
    auto result = Jpeg {};
    static const auto begin_tag = std::regex("<jpeg(.*)>");
    static const auto end_tag = std::regex("</jpeg(.*)>");
    std::string line, hex_buffer;
    if(not std::getline(is, line)) throw std::runtime_error("end of file");
    std::smatch match;
    if (not std::regex_match(line, match, begin_tag)) throw std::runtime_error("not a <jpeg_>");
    result.name = match[1];

    while (std::getline(is, line))
    {
        if (std::regex_match(line, match, end_tag)) { break; }
        std::istringstream hexes { line };
        read_bytes(std::back_inserter(result.data), hexes);
    }


    return result;
}

int main()
{
    std::istringstream input_stream(test_data);
    auto jpeg = read_jpeg(input_stream);

    std::cout << jpeg << std::endl;
}

预期产出:

1 : [ ff, d8, ff, e0, 00, 10, 4a, 46, 49, 46, 00, 01, 01, 01, 00, 60, 12, 34, 56, 78, 9a, bc, de, f0 ]