Write a new section in ini

This is the forum for miscellaneous technical/programming questions.

Moderator: 2ffat

Write a new section in ini

Postby Lena » Thu Nov 23, 2017 6:12 am

Hi.
I want to consult on this issue:
The names of sections in my ini file are such <int>:
Code: Select all
[1]
name=Паста "Di Bocca"
price=210
text=
weight=400 г.
footer=(спагетти с креветками, морским гребешком, кальмаром, осьминогом и мидиями, приготовленные в сливочном соусе со свежими томатами, перцем Чили, чесноком и розмарином)
category=Пасты и ризотто
image=1.jpg
print=1
otdel=0

[2]
name=Паста "Неро"
price=170
text=
weight=420 г.
footer=(спагетти с чернилами каракатицы, тушеные в сливочном соусе с креветками, с мидиями, кальмарами, осьминогами, томатами, чесноком и белым вином)
category=Пасты и ризотто
image=2.jpg
print=1
otdel=0

[8]
name=Паста "Болоньезе"
price=135
text=
weight=360 г.
footer=(знаменитая паста с мясным соусом Болоньезе и сыром Пармезан)
category=Пасты и ризотто
image=8.jpg
print=1
otdel=0

//***


When I write a new section, I want to get a unique new value. The section name must be equal image=.
I chose this way:
Code: Select all
std::vector<int> NameOfSection; //global
//***
std::unique_ptr<TMemIniFile> FileINI(new TMemIniFile(path, TEncoding::UTF8));
     std::unique_ptr<TStringList> AlliniSection(new TStringList());
     FileINI->ReadSections(AlliniSection.get());

      NameOfSection.clear();
    for (int i = 0; i < AlliniSection->Count; i++)
     {
      //check int 1... 2... 30... 135...
      try
       {
        int check = StrToInt(AlliniSection->Strings[i]);
        NameOfSection.push_back(check);
       }
       catch(...)
         {
          ShowMessage(L"No int in name of Section dibocca.ini");
          return;
         }
     }

     std::vector<int>::iterator maxnum = std::max_element(NameOfSection.begin(), NameOfSection.end());
     int num =  *maxnum + 1;
     LabelNameImage->Caption = L"The name of the photo should be: " +
     IntToStr(num) + L".jpg";


Code: Select all
//Write a new section to a file
std::unique_ptr<TMemIniFile> FileINI(new TMemIniFile(path, TEncoding::UTF8));
   
     std::vector<int>::iterator maxnum = std::max_element(NameOfSection.begin(), NameOfSection.end());
     int num =  *maxnum + 1;
//***
 FileINI->WriteString(IntToStr(num), L"image",  IntToStr(num)+L".jpg");
//***
FileINI->UpdateFile();

It seems everything is right and works. Is this the optimal solution?

P.S.
And the second question...
I have string with one number:
Code: Select all
//Example
Итого: 250 грн.
//or
Итого: 1100 грн.
//or
Итого: 800 грн.
//***

What is the best way to read into a int variable number from this string?
Lena
BCBJ Master
BCBJ Master
 
Posts: 526
Joined: Sun Feb 06, 2011 1:28 pm

Re: Write a new section in ini

Postby Lena » Mon Nov 27, 2017 10:16 am

And the second question...
I have string with one number:


I try this:
Code: Select all
#include <System.RegularExpressions.hpp>
    String ChekDig = L"Итого: 605 грн.";
    std::auto_ptr<TRegEx> re(new TRegEx(L"(\\d+)"));
    int v = StrToInt(re->Match(ChekDig).Value);

E2285 Could not find a match for 'TRegEx::TRegEx(const wchar_t *)'
Lena
BCBJ Master
BCBJ Master
 
Posts: 526
Joined: Sun Feb 06, 2011 1:28 pm

Re: Write a new section in ini

Postby rlebeau » Mon Nov 27, 2017 8:32 pm

Lena wrote:When I write a new section, I want to get a unique new value. The section name must be equal image=.


If the filename is always derived from the section name, then what's the point of storing the filename explicitly at all?

Lena wrote:I chose this way:
...
It seems everything is right and works. Is this the optimal solution?


Sure, if your section names are sequential. But what if there are gaps between them? For instance, if sections get deleted over time. You could use one of those missing numbers instead of calculating the next largest value. To do that, sort the vector and then iterate through it. If two adjacent elements do not have consecutive values, pick a random number between those two values (or, just the next available number in the sequence). If you end up at the end of the vector, then all section names were consecutive, so use the next highest number instead. For example (untested):

Code: Select all
//#include <random>

std::vector<int> NameOfSection; //global
...
NameOfSection.clear();
for (int i = 0; i < AlliniSection->Count; ++i)
{
    int check;
    if (TryStrToInt(AlliniSection->Strings[i], check))
        NameOfSection.push_back(check);
}

int num;
if (NameOfSection.empty())
{
    num = 1;
}
else
{
    if (NameOfSection.size() > 1)
        std::sort(NameOfSection.begin(), NameOfSection.end());

    auto iter = NameOfSection.begin();
    auto last = NameOfSection.end() - 1;

    do
    {
        if (iter == last)
        {
            num = (*iter) + 1;
            break;
        }

        if (*(iter + 1) != ((*iter) + 1))
        {
            num = (*iter) + 1;
            /* or:
            std::random_device rd;
            std::mt19937 rng(rd());
            std::uniform_int_distribution<int> uni((*iter) + 1, (*(iter + 1))-1);
            num = uni(rng);
            */
            break;
        }

        ++iter;
    }
    while (true);
}


Alternatively:

Code: Select all
//#include <random>
#include <numeric>

std::vector<int> NameOfSection; //global
...
NameOfSection.clear();
for (int i = 0; i < AlliniSection->Count; ++i)
{
    int check;
    if (TryStrToInt(AlliniSection->Strings[i], check))
        NameOfSection.push_back(check);
}

int num;
if (NameOfSection.empty())
{
    num = 1;
}
else
{
    if (NameOfSection.size() > 1)
        std::sort(NameOfSection.begin(), NameOfSection.end());

    std::adjacent_difference(NameOfSection.begin(), NameOfSection.end(), NameOfSection.begin());
   
    auto iter = NameOfSection.begin();
    num = *iter++;

    do
    {
        if (iter == NameOfSection.end())
        {
            ++num;
            break;
        }

        if (*iter != 1)
        {
            ++num;
            /* or:
            std::random_device rd;
            std::mt19937 rng(rd());
            std::uniform_int_distribution<int> uni(num + 1, num + (*iter) - 1);
            num = uni(rng);
            */
            break;
        }

        ++num;
        ++iter;
    }
}


Lena wrote:I have string with one number:
...
What is the best way to read into a int variable number from this string?


I don't generally use regular expressions. What you showed could easily be parsed using the STL via std::wistringstream instead, eg:

Code: Select all
#include <string>
#include <sstream>

std::wstring input = L"Итого: 250 грн.";

std::wistringstream iss(input);
std::wstring ignore;
int number;

if (iss >> ignore >> number)
// or: if (std::getline(iss, ignore, L':') && (iss >> number))
{
    // use number as needed...
}


Lena wrote:I try this:
...
E2285 Could not find a match for 'TRegEx::TRegEx(const wchar_t *)'


If you read the documentation, you will see that TRegEx does not have a constructor that takes a single wchar_t* as input. It's constructor takes a System::String and a TRegExOptions as input. The TRegExOptions is supposed to have a default value, but like most things in the RTL, TRegEx is written in Delphi, and depending on which version of C++Builder are you using, the constructor might not have a default value for the TRegExOptions parameter in C++ (in fact, the documentation even shows that)! Double-check your .hpp file to verify.

So, either provide that second parameter, eg:

Code: Select all
std::unique_ptr<TRegEx> re(new TRegEx(L"(\\d+)", TRegExOptions() << roNotEmpty));


Or else use one of the 'static' methods instead of constructing a TRegEx object manually, eg:

Code: Select all
int v = StrToInt(TRegEx::Match(ChekDig, L"(\\d+)").Value);
Remy Lebeau (TeamB)
Lebeau Software
User avatar
rlebeau
BCBJ Author
BCBJ Author
 
Posts: 1457
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA

Re: Write a new section in ini

Postby Lena » Fri Dec 01, 2017 2:10 am

Thank You very much for the very useful code!
Lena
BCBJ Master
BCBJ Master
 
Posts: 526
Joined: Sun Feb 06, 2011 1:28 pm


Return to Technical

Who is online

Users browsing this forum: Bing [Bot] and 16 guests

cron