我有一个包含一些值的字符串向量。这些值应该是十六进制字节,但是作为字符串存储在此向量中。 实际上是从文本文件中读取字节,如下所示:
(文本文件的内容)
<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”解决方案对我有用,我也会尝试其他用户提供的解决方案。
答案 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 ]