Home > Software engineering >  Reading custom (.ndev) Json-like file structure
Reading custom (.ndev) Json-like file structure

Time:01-19

I'm currently creating a custom file structure (File extension is .ndev), to increase my skill in working with files in C . I can save values to a file in a specific way (See below)

{
    "username": "Nikkie",
    "password": "test",
    "role": "Developer",
    "email": "[email protected]"
}

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

My question is, how can I read the value of one of those variables with C , without it coming out like the screenshot below:

enter image description here

My current code to write the file:

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

My current code to read the file:

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!");
    }
}

I just can't seem to get it to display the values properly, there are also no errors listed in the console nor in the VS debug build.

CodePudding user response:

From a practical point of view, there is no reason to store your structure in that format. There are simpler ways.

Anyhow, here's a starting point (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;
  }
}
  •  Tags:  
  • Related