[英]Convert vector<string> to unsigned char array in C++
我有一个字符串向量,其中包含一些值。 这些值应为十六进制字节,但将作为字符串存储在此向量中。 这些字节实际上是从文本文件内部读取的,如下所示:
( 文本文件的内容 )
<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
我想要的是,我想将这些字节存储在一个无符号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”解决方案已为我工作,我将尝试其他用户提供的解决方案。
我什至不会经历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
来消除语言环境废话,这可能会破坏您的解析功能(尽管对于浮点解析来说更std::from_chars
),并且没有充分的理由使其变慢。
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
}
如果您使用的是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);
您可以在每个值上使用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
这是一个完整的解决方案,包括一个测试和一个基本的解析器(为简单起见,它假定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 ]
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.