У меня есть строка вида:
0002010212431438742295520465365303566540810000.005802NG5917Arinfbnuattest4086005Lagos61052340163049091
Мне нужно разобрать каждый токен, содержащийся в тексте, в структуру из трех членов, таких как
struct token {
string id;
int length;
string value;
};
Каждый токен можно идентифицировать, используя его первый текст (длиной 2) (от 00 до 99), который является его идентификатором.
Затем за идентификатором следует числовое значение, которое представляет длину значения, следующего за элементом, за которым следует длина.
Проблема здесь в том, что некоторые идентификаторы (токены) также представляют собой коллекцию токенов, каждый из которых имеет идентификатор, начиная с 00 … Я попытался решить это следующим образом …
tlv* Decoder::parsetlv(std::string data)
{
tlv* root = new tlv();
tlv* tlv_list = root;
tlv* temp = nullptr;for (size_t index = 0; index < data.length(); temp = tlv_list, tlv_list = tlv_list->next) {
if (!tlv_list) {
temp->next = new tlv();
tlv_list = temp->next;
}tlv_list->Id = data.substr(index, 2);
auto tempId = tlv_list->Id;
index = index + 2;
tlv_list->length = data.substr(index, 2);
index = index + 2;
int length = atoi(tlv_list->length.c_str());
tlv_list->value = data.substr(index, length);
if (any_of(_parentTagsIdentifiers, 72, tlv_list->Id)) {
//place of horror
tlv_list->child = tlv_list;
}
index = index + length;
}
return root;
}
Проблема, которую я обнаружил в своей реализации, заключается в том, что дочерний идентификатор путают как родительский идентификатор, так как они имеют одинаковый идентификатор, в отличие от того, что родительский идентификатор находится под так называемым корневым идентификатором, в то время как дочерний идентификатор находится под (после) другой идентификатор, который в этом случае называется идентификатором шаблона.
В моей реализации я использую некоторый связанный список, но идеи с использованием любого контейнера с ++ приветствуются.
РЕДАКТИРОВАТЬ
это реализация, которая использовала декодер ()
const char* doToString(const char * dataId)
{
if (strncmp("00", dataId, 2) == 0) {
return "Payload Format";
}
else if (strncmp("01", dataId, 2) == 0) {
return "Point of Initiation Method";
}
else if (strncmp("02", dataId, 2) == 0) {
return "Visa Card id";
}
else if (strncmp("52", dataId, 2) == 0) {
return "Merchant Category code";
}
else if (strncmp("53", dataId, 2) == 0) {
return "Transaction Currency Code";
}
else if (strncmp("54", dataId, 2) == 0) {
return "Transaction Amount";
}
else if (strncmp("55", dataId, 2) == 0) {
return "Tip or Convinience Indicator";
}
else if (strncmp("56", dataId, 2) == 0) {
return "Value of Convinience Fee Fixed";
}
else if (strncmp("57", dataId, 2) == 0) {
return "Value of Convinience Fee Fixed";
}
else if (strncmp("58", dataId, 2) == 0) {
return "Country Code";
}
else if (strncmp("59", dataId, 2) == 0) {
return "Merchant Name";
}
else if (strncmp("60", dataId, 2) == 0) {
return "Merchant City";
}
else if (strncmp("61", dataId, 2) == 0) {
return "Merchant Postal Code";
}
else if (strncmp("62", dataId, 2) == 0) {
return "Additional Data Field Template";
}
else if (strncmp("63", dataId, 2) == 0) {
return "Cyclic Redundancy Check";
}
else if (strncmp("64", dataId, 2) == 0) {
return "Merchant Info Lang Template";
}
}
void realTostring(string data) {
Qr::Decoder dec;
const Qr::tlv* head = dec.parsetlv(data);
const Qr::tlv* qr = head;
string name;
while (qr) {
if (!qr->child) {
std::cout << doToString(qr->Id.c_str()) << " " << qr->length << " "<< qr->value << std::endl;
}
else if(qr->child) {
std::cout << qr->Id;
std::cout << "Additional Child" <<" "<< qr->child->Id << " "<< qr->child->length <<" "<<qr->child->value << std::endl;
}
qr = qr->next;
}
deleteTlv(head);
}
это выход
Payload Format 02 01
02Additional Child 02 12 431438742295
Merchant Category code 04 6536
Transaction Currency Code 03 566
Transaction Amount 08 10000.00
Country Code 02 NG
Merchant Name 17 Arinfbnuattest408
Merchant City 05 Lagos
Merchant Postal Code 05 23401
Cyclic Redundancy Check 04 9091
из выходной второй строки он показывает, что обрабатывает токен с идентификатором 02 как дочерний идентификатор для идентификатора шаблона, равного 62, потому что они имеют одинаковый идентификатор, вторая строка должна быть для
ID карты Visa
Ниже приведен пример кода для разбивки данных в формат TLV. Посмотрите, как это работает здесь:
#include <iostream>
#include <vector>
#include <string>
#include <cstdio>
using namespace std;
class TLV
{
public:
string tag;
unsigned int length;
string value;
TLV(string data)
{
value = "";
//If there is enough data
if(data.length() >= 4)
{
tag = data.substr(0,2);
sscanf(data.substr(2,4).c_str(),"%2x",&length);
//If there is enough data
if(data.length() >= 4 + length*2) value = data.substr(4,length*2);
}
}
static void parseTLV(string data, vector<TLV*> &res)
{
while(data.length() >= 4)
{
TLV *t = new TLV(data);
if(t->value == "") break;
res.push_back(t);
data = data.substr(4+(t->length+t->length));
}
if(data.length() != 0)
{
//Whole data is not in TLV format. Can throw some error
cout<<"ERROR [1] :: ["<<data<<"]\n";
}
}
};int main()
{
string data = "0007AAAAAAAAAAAAAA010FAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0220AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
vector<TLV*> res;
TLV::parseTLV(data, res);
for(TLV *t:res)
{
printf("%s | %02X | %s |\n",t->tag.c_str(),t->length,t->value.c_str());
}
return 0;
}
Других решений пока нет …