读取自定义 (.ndev) Json 类文件结构

Reading custom (.ndev) Json-like file structure

我目前正在创建自定义文件结构(文件扩展名为 .ndev),以提高我在 C++ 中处理文件的技能。我可以以特定方式将值保存到文件中(见下文)

{
    "username": "Nikkie",
    "password": "test",
    "role": "Developer",
    "email": "test@gmail.com"
}

This doesn't have anything to do with actual JSON, it's just structured like it.

我的问题是,如何使用 C++ 读取其中一个变量的值,而不像下面的屏幕截图那样显示出来:

我当前写入文件的代码:

void user::RegisterUser(string username, string password, string role, string email)
{

    string filename = "E:\Coding\C\test\data\" + username + ".ndev";

    ifstream CheckFile(filename);

    if (CheckFile.good())
    {
        printf("User already exists!");
    }

    else {
        ofstream UserDataFile(filename);

        UserDataFile << "{\n\t\"username\": \"" << username << "\",\n\t\"password\": \"" << password << "\",\n\t\"role\": \"" << role << "\",\n\t\"email\": \"" << email << "\"\n}";
        UserDataFile.close();
    }

    CheckFile.close();
}

Don't bludgeon me about the password encryption, I will add that later. I'm currently trying to actually let it read the values before I do anything else

我当前读取文件的代码:

void user::LoginUser(string username)
{
    string filename = "E:/Coding/C/test/data/" + username + ".ndev";

    ifstream UserFile(filename, ios_base::in);

    if (UserFile.good())
    {
        string name;
        string passw;
        string role;
        string email;

        while (UserFile >> name >> passw >> role >> email)
        {
            cout << name << passw << endl;
            cout << role << email << endl;
        }
    }

    else
    {
        printf("User doesn't exist!");
    }
}

我似乎无法让它正确显示值,控制台和 VS 调试版本中也没有列出任何错误。

从实用的角度来看,没有理由以这种格式存储您的结构。还有更简单的方法。

无论如何,这是一个起点(demo):

#include <iostream>
#include <string>
#include <map>
#include <iomanip>
#include <fstream>

using namespace std;

// your structure
struct person
{
  string name, pass, role, mail;
};

// the tokens your format is using
enum class token : char
{
  lb = '{',
  rb = '}',
  sc = ':',
  comma = ',',
  str,
  end
};

token tk; // current token
string str; // if the current token is token::str, str is its value

// get_token breaks the input stream into tokens - this is the lexer, or tokenizer, or scanner
token get_token(istream& is)
{
  char c;
  if (!(is >> c))
    return tk = token::end;
  switch (c)
  {
  case '{':
  case '}':
  case ':':
  case ',':
    return tk = token(c);
  case '"':
    is.unget();
    is >> quoted(str);
    return tk = token::str;
  default: throw "unexpected char";
  }
}

// throws if the current token is not the expected one
void expect(istream& is, token expected, const char* error)
{
  if (tk != expected)
    throw error;
  get_token(is);
}

// throws if the current token is not a string
string expect_str(istream& is, const char* error)
{
  if (tk != token::str)
    throw error;
  string s = str;
  get_token(is);
  return s;
}

// the actual parser; it extracts the tokens one by oneand compares them with the expected order.
// if the order is not what it expects, it throws an exception.
void read(istream& is, person& p)
{
  get_token(is); // prepare the first token

  expect(is, token::lb, "'{' expected");

  map<string, string> m; // key/values storage
  while (tk == token::str)
  {
    string k = expect_str(is, "key expected");
    expect(is, token::sc, "':' expected");
    string v = expect_str(is, "value expected");

    if (m.find(k) == m.end())
      m[k] = v;
    else
      throw "duplicated key";

    if (tk == token::comma)
      get_token(is);
    else
      break; // end of of key/value pairs
  }

  expect(is, token::rb, "'}' expected");
  expect(is, token::end, "eof expected");

  // check the size of m & the keys & copy from m to p
  // ...
}

int main()
{
  ifstream is{ "c:/temp/test.txt" };
  if (!is)
    return -1;

  try
  {
    person p;
    read(is, p);
  }
  catch (const char* e)
  {
    cout << e;
  }
}