C++ TStringsList parse explanation - c++

I'm trying to read a ini file in a value listbox.
Example below works, but i don't know why.
ReadSectionValues contains a string list of ini lines.
How does Rad Studio parse the lines with:
ListValues->Names[i] is first part of the line and ListValues->Values[ListValues->Names[i]] is the second part?
int i;
try
{
//ShowMessage( ListBox1->Items->Strings[ListBox1->ItemIndex] );
TStringList *ListValues = new TStringList;
TIniFile* SettingsFile = new TIniFile(ExtractFilePath(Application->ExeName) + "settings.ini");
String s;
s = ListBox1->Items->Strings[ListBox1->ItemIndex];
SettingsFile->ReadSectionValues( s , ListValues);
for (i = 0; i < (ListValues->Count); i++) {
//ShowMessage(ListValues->Names[i]);
//ShowMessage(ListValues->Values[ListValues->Names[i]]);
vList1->InsertRow(ListValues->Names[i] , ListValues->Values[ListValues->Names[i]],True);
}
delete SettingsFile;
delete ListValues;
}
catch(Exception* e)
{
ShowMessage(e->Message);
}
Please explain, Rad stuido help found no explanation.

void __fastcall ReadSectionValues(
const System::UnicodeString Section,
System::Classes::TStrings* Strings
)
is a method, which gets all lines of ini-file section with name Section and stores them in TStrings-object Strings. Note that these strings have format name=value.
TStrings class has two access properties Names and Values. Their parse algorithm is very simple. If you get stringsObject->Values[1] it takes second line from stringsObject and splits it into two strings on = (or other value of NameValueSeparator property of stringsObject). The string to the left of = (separator) is returned as name (by property Name) and the string to the right of = is returned as value (by property Value).

Related

C++ Builder - Copy a Link to a String Based On Certain Words in It

This's my first post here.
I have 4 links in a Memo or TStringList:
http://website.com/text/book&id=20/programming
http://website.com/text/book&id=10/programming
http://website.com/text/book&id=40/programming
http://website.com/text/book&id=30/programming
What I want to do is to copy each link based on its "id number", as shown above to separate string, and NOT based on its
index in TMemo or in TStringList.
This's because the id number of each link is always change every time or dynamics (it's a random id).
So let's say :
if the link containts id=10 then it should be copied to a string called "id10".
final result is id10 containts: http://website.com/text/book&id=10/programming
if the link containts id=30 then it should be copied to a string called "id30".
final result is id30 containts: http://website.com/text/book&id=30/programming
so on and on until all links are copied into a separate different string.
I've tried to resolve this problem using substring function, such as:
int p = 0;
String id10, id20, id30, id40;
p = Memo1->Lines->Text.Pos("id=20");
if (p != 0)
{
id10 = Memo1->Lines->Text.SubString(p + 1, Memo1->Lines->Text.Length());
ShowMessage(id10);
}
......
Unfortunately, its always failed. Because I am new to c++ and the sort but I don't know what to do with all of it. I am sorry.
So I need your help to handle this situation.
Thank you very much.
Calling .Pos() from the text property is getting the index for the position of the found string within the entire text of the memo control. Here is a short example of how to read each line from a TMemo in C++ Builder:
AnsiString id10;
for (int i = 0; i < Memo1->Lines->Count; i++)
{
AnsiString line = Memo1->Lines->Strings[i];
if (line.Pos("id=10") > 0)
{
id10 = line;
ShowMessage(id10);
}
}
Using the above snippet, you should be able to deduce how to make it do what you want.

How do I extract a single character from a line and put it in a const char*

I have a text file which I'm going through line by line and taking relevant information from.
However, one of these lines I cannot seem to take the appropriate information from. I'm trying to take a single char from this line and put it into a const char*
The line is like this:
"character" "B"
And I'm trying to extract the 'B' character from inside the quotation marks.
std::string Output;
int Quotations = 0;
for (int i = 0; i < LineText.size(); ++i)
{
if ('"' == LineText[i])
{
Quotations += 1;
if (3 == Quotations)
{
Output += LineText[i + 1];
break;
}
}
}
return Output.c_str();
I'm grabbing the line just fine and also counting the quotation marks correctly but for some reason the outputted result is:
/=�UL��'F/�$/U�
Rather than:
B
Any ideas where I'm going wrong?
Thanks in advanced.
You return a pointer to local data. The Output string goes out of scope as soon as the function returns, and the pointer is then invalid.
Why don't you return a std::string instead?

Split string and get values before different delimiters

Given the code:
procedure example {
x=3;
y = z +c ;
while p {
b = a+c ;
}
}
I would like to split the code by using the delimiters {, ;, and }.
After splitting, I would like to get the information before it together with the delimiter.
So for example, I would like to get procedure example {, x=3;, y=z+c;, }. Then I would like to push it into a list<pair<int, string>> sList. Could someone explain how this can be done in c++?
I tried following this example: Parse (split) a string in C++ using string delimiter (standard C++), but I could only get one token. I want the entire line. I am new to c++, and the list, splitting, etc. is confusing.
Edit: So I have implemented it, and this is the code:
size_t openCurlyBracket = lines.find("{");
size_t closeCurlyBracket = lines.find("}");
size_t semiColon = lines.find(";");
if (semiColon != string::npos) {
cout << lines.substr(0, semiColon + 1) + "\n";
}
However, it seems that it can't separate based on semicolon separately, openBracket and closeBracket. Anyone knows how to separate based on these characters individually?
2nd Edit:
I have done this (codes below). It is separating correctly, I have one for open curly bracket. I was planning on adding the value to the list in the commented area below. However, when i think about it, if i do that, then the order of information in the list will be messed up. As i have another while loop which separates based on open curly bracket. Any idea on how i can add the information in an order?
Example:
1. procedure example {
2. x=3;
3. y = z+c
4. while p{
and so on.
while (semiColon != string::npos) {
semiColon++;
//add list here
semiColon = lines.find(';',semiColon);
}
I think that you should read about std::string::find_first_of function.
Searches the string for the first character that matches any of the characters specified in its arguments.
I have a problem to understand what you really want to achieve. Let's say this is an example of the find_first_of function use.
list<string> split(string lines)
{
list<string> result;
size_t position = 0;
while((position = lines.find_first_of("{};\n")) != string::npos)
{
if(lines[position] != '\n')
{
result.push_back(lines.substr(0, position+1));
}
lines = lines.substr(position+1);
}
return result;
}

Reading a random line from a txt file, then trim it in QT SDK

I'd like to ask your help with my little school project.
The task is to determine a person's gender (using 2 radio buttons) and then pick a random Japanese family name and male/female middlename. And there's the rest of the task, but it's nothing compared to this part :(
Thing is, i have managed to make the 3 .txt files (familynames.txt, malemiddlenames.txt and femalemiddlenames.txt) look like the following:
1,Akiro
2,Sakura
3,etc...
What i'd like to do is create a random number, and read the lines until it arrives to the line with the same number as my random number, then cut the number and the comma off, and display the name on the corresponding label. So far this is what i've got:
void MainWindow::famname()
{
QString familyname;
int famrand =qrand() % 76;
ui->label_2->setText(QString::number(famrand));
int i = 1;
QFile famfile("C:\Users\Ryseth\gyakorlas\_familynames.txt");
QTextStream in(&famfile);
if(famfile.open(QIODevice::ReadOnly)){
while (!in.atEnd()) {
QString line = in.readLine();
i++;
if(i==famrand){
QStringList line2 =line.split(',');
familyname = line2.at(0);
ui->label_2->setText(QString::number(famrand)+" "+QString::number(i));
ui->FamilyLabel->setText(familyname);
}//IF
}//WHILE
}//IF
famfile.close();
}//NGEN
If any of you could think of some sort of solution or if you have ANY suggestions, please don't hasitate to share it with me :D
Thank you, and have a nice day/night : Ruben
I think with Boost::Spirit::Qi you could parse your file into a std::vector< std::string > and do your operation with simple c++ methods.
But to help you with your Qt-Solution:
You never check if int famrand =qrand() % 76; produces a legal number, are there enough entries in your text file ...
int i = 1; This integer is unnecessary, the number is within the text file ...
My solution (untested):
while (!in.atEnd()) {
QString line = in.readLine();
QStringList list = line.split(",", QString::SkipEmptyParts);
bool ok;
int idx = list.at(0).toInt(&ok);
if (ok && idx == famrand) {
familyname = list.at(1).trimmed();
// ... do with your ui whatever you want
}//IF
}//WHILE
Keep in mind you have to do error handling if the conversion of string to int fails and/or the accessors of list throw (list.at(xx))
The positive thing is, you dont need an ordered text file!
I don't really understand what you are managing to do but at this line I guess you are getting the number, not the familyname.
familyname = line2.at(0); // number
familyname = line2.at(1); // family name

Match beginning of file to string literal

I'm working with a multi line text block where I need to divide everything into 3 groups
1: beginning of the file up to a string literal // don't keep
2: The next line //KEEP THE LINE FOLLOWING STRING LITERAL
3: Everything following that line to the end of file. // don't keep
<<
aFirstLing here
aSecondLine here
MyStringLiteral //marks the next line as the target to keep
What I want to Keep!
all kinds of crap that I don't
<<
I'm finding plenty of ways to pull from the beginning of a line but am unable to see how to include an unknown number of non-blank lines until I reach that string literal.
EDIT: I'm removing the .net-ness to focus on regex only. Perhaps this is a place for understanding backreferences?
Rather than read the entire file into memory, just read what you need:
List<string> TopLines = new List<string>();
string prevLine = string.Empty;
foreach (var link in File.ReadLines(filename))
{
TopLines.Add(line);
if (prevLine == Literal)
{
break;
}
prevLine = line;
}
I suppose there's a LINQ solution, although I don't know what it is.
EDIT:
If you already have the text of the email in you application (as a string), you have to split it into lines first. You can do that with String.Split, splitting on newlines, or you can create a StringReader and read it line-by-line. The logic above still applies, but rather than File.ReadLines, just use foreach on the array of lines.
EDIT 2:
The following LINQ might do it:
TopLines = File.ReadLines(filename).TakeWhile(s => s != Literal).ToList();
TopLines.Add(Literal);
Or, if the strings are already in a list:
TopLines = lines.TakeWhile(s => s != Literal).ToList();
TopLines.Add(Literal);
.*(^MyStringLiteral\r?\n)([\w|\s][^\r\n]+)(.+) seems to work. the trick wasn't back references - it was the exclusion of \r\n.
File.ReadAllLines() will give you an array you can iterate over until you find your literal, then take the next line
string[] lines = File.ReadAllLines();
for(int i;i<lines.Length;i++)
{
if(line == Literal)
return lines[i + 1];
}