PDA

View Full Version : Parse a QString with a 'QSettings style'



franco.amato
15th June 2015, 08:18
Good morning,
I would parse the content of a QString like if it were a QSettings ( the QString contains groups ).

And I would take only the content of the QString matching a specific group ( selected by a QComboBox ).

For example this is the content of a QString

[Group1]
clusteringFactor=4
minimumHitsCount=15
minimumHitsRate=0.005
collationGap=16
minimumMatchRate=0.65
[Group2]
clusteringFactor=3
minimumHitsCount=20
minimumHitsRate=0.008
collationGap=16
minimumMatchRate=0.65
[Group3]
clusteringFactor=2
minimumHitsCount=20
minimumHitsRate=0.01
collationGap=8
minimumMatchRate=0.7

And if the QComboBox is selected over Group2, I only would take the sub string

clusteringFactor=3
minimumHitsCount=20
minimumHitsRate=0.008
collationGap=16
minimumMatchRate=0.65
Is there a fast way to do it, or I have to use regular expressions?
Thanx in advance for the help

jefftee
15th June 2015, 16:45
Is there a reason you can't or don't want to use QSettings?

franco.amato
15th June 2015, 16:51
Hi thanx for your reply.
Sure I would use QSettings but unlikely the data is contained in a qstring
so I need to parse it

d_stranz
15th June 2015, 17:54
Sure I would use QSettings but unlikely the data is contained in a qstring

You can use QSettings for this, but you have to register your own format and implement at least the read function. Look at this post (http://www.qtcentre.org/threads/59733-QMetaType-dynamic-object-creation-and-initialization) where I post code that reads and writes QSettings from XML strings, and look at QSettings::registerFormat(). As long as your string has delimiters that allow the individual values to be split out, then a custom reader would be easy to write and you can use the QSettings interface to retrieve whatever you want without having to reinvent that wheel, too.

stampede
15th June 2015, 18:01
Maybe I am wrong, but isn't it the "ini" format already ? Can't the OP simply save the string to temporary file and let QSettings load and parse it ?

d_stranz
15th June 2015, 18:09
Can't the OP simply save the string to temporary file and let QSettings load and parse it ?

Yep, that is certainly another option and probably easier than implementing a custom format. One wonders where the OP's list of settings comes from in the first place, if not from a file.

The QSettings read and write functions take a reference to a QIODevice so anything derived from that will work. The main trick is maintaining the hierarchical structure of the settings if there are nested groups.

franco.amato
15th June 2015, 18:22
I didn't think to save the qstring to a temporary file,
very good idea.

Thanx

jefftee
15th June 2015, 18:46
If you *must* parse this yourself, here's a QRegularExpression (not QRegExp) that will work to create matches for the group name and the contents for the group. Should be trivial exercise then to parse the contents of the group into lines and then key=value pairs for each line, etc.

https://regex101.com/r/hY4iY7/1

franco.amato
16th June 2015, 00:06
I can not use QRegularExpression as I'm developing under Ubuntu 12 that does not support Qt5.x

Added after 1 13 minutes:

I tried to use a QTemporary file to temporary store the QString content, but I can not as I can not give to it a .ini extension
Do you have an idea on how do it?
Regards

jefftee
16th June 2015, 00:15
Why can't you give it an .ini extension? Please show relevant code and/or errors, etc.

Edit: and I'm not even sure that QSettings cares about the filename since one of the overloaded contructors allows you to specify a filename and the format, etc.

franco.amato
16th June 2015, 00:23
Here some relevant code


QVariantMap PreferencesDialog::searchPreferences() const
{
QString text = m_ui->searchPreferencesEdit->toPlainText(); // text contains my keys/values

QTemporaryFile tmpFile;
if(!tmpFile.open())
{
//return;
}

// Here I will parse the "text" string

tmpFile.write(text.toUtf8());

const QString fileName = tmpFile.fileName();

QSettings settings( fileName, QSettings::NativeFormat );
settings.beginGroup(m_searchPreferencesGroup);
settings.endGroup();

// .... here I should read the pairs keys/values
}

So how can I specify the temporary file extension? I think I have to use a normal file

Regards

jefftee
16th June 2015, 00:31
You should really familiarize yourself with the Qt documentation. These questions are readily answered in the documentation.

The QTemporaryFile class documentation shows overloaded constructors that you can specify a template name. For example:



QTemporaryFile temp_file("my_fake_settings_file_XXXXXX.ini");

Again, that's assuming that your fake settings file even needs to have an extension of .ini. If you read the doc for QSettings, there is an overloaded constructor that you can provide both the filename and the settings format, so my guess is that you could provide any filename you want, etc.

Edit: In your example, you use QSettings::NativeFormat, did you notice there's a QSettings::IniFormat too?

franco.amato
16th June 2015, 01:00
Well if you also read the documentation you will see that NativeFormat under Linux corresponds to a ini file :-)

Added after 8 minutes:

Anyway I can not get it working

jefftee
16th June 2015, 01:04
I'm quite aware of that, but I'm left guessing what the issue is... You posted your code, but don't say what the problem is. I can only assume it's not working, but it would certainly help to show what you have tried and what error(s) you get, etc.

My suggestion to use QSettings::IniFormat was because regardless of the platform you're using, the data you have in your QString is in ini format. While NativeFormat may work for you now, if you port to some other platform, it would seem to me that IniFormat would always work.

So back to the issue at hand, what error(s) are you receiving from the code you posted earlier?

P.S. I would do tmpFile.setAutoRemove(false) and close() your tmpFile before instantiating your QSettings, or minimally tmpFile.flush() to ensure it's all written to disk. Probably low risk of having a problem with that, but if you do, it will be a hard to find bug.

Edit: The following code works for me:



QTemporaryFile tmpFile;
tmpFile.setAutoRemove(false);

if(!tmpFile.open())
{
return;
}

QString text = "[Group1]\nclusteringFactor=4\nminimumHitsCount=15\nminimum HitsRate=0.005\ncollationGap=16\nminimumMatchRate= 0.65";

// Here I will parse the "text" string

tmpFile.write(text.toUtf8());

const QString fileName = tmpFile.fileName();
tmpFile.close();

QSettings settings( fileName, QSettings::IniFormat );
settings.beginGroup("Group1");
int clusteringFactor = settings.value("clusteringFactor").toInt();
int minimumHitsCount = settings.value("minimumHitsCount").toInt();
settings.endGroup();


I'm on a Mac platform and the QTemporaryFile filename generated w/o an .ini extension works just fine as seen above.

franco.amato
16th June 2015, 05:13
Well seems that I can not extract the data from the temporary file.
I can see the file content and the text is there so I don't understand.
This is the code



QString text = m_ui->searchPreferencesEdit->toPlainText();

QTemporaryFile tmpFile("tmp_file_XXXXXX.ini");
if(!tmpFile.open())
{
//return;
}

// Here I will parse the "text" string

tmpFile.write(text.toUtf8());

const QString fileName = tmpFile.fileName();

QSettings settings( fileName, QSettings::IniFormat );
settings.beginGroup(m_searchPreferencesGroup);
qDebug() << "childkeys=" << settings.allKeys(); // allKeys is empty
settings.endGroup();


This is the content of the file:


[Group1]
clusteringFactor=4
minimumHitsCount=15
minimumHitsRate=0.005
collationGap=16
minimumMatchRate=0.65
[Group2]
clusteringFactor=3
minimumHitsCount=20
minimumHitsRate=0.008
collationGap=16
minimumMatchRate=0.65
[Group3]
clusteringFactor=2
minimumHitsCount=20
minimumHitsRate=0.01
collationGap=8
minimumMatchRate=0.7

And the value of
m_searchPreferencesGroup is "Group1" so I should be able to
get the following keys, values:

clusteringFactor=4
minimumHitsCount=15
minimumHitsRate=0.005
collationGap=16
minimumMatchRate=0.65

But I don't get nothing :-(

Any idea? Where I am wrong?

jefftee
16th June 2015, 05:55
What happens when you run the code I posted above that shows a working example?

franco.amato
16th June 2015, 06:17
I got some output....don't know why.
So seems that I need to remove the file manually?

jefftee
16th June 2015, 07:07
More importantly, I added a tmpFile.close() to your example.

You were never closing the QTemporaryFile before trying to use it with QSettings. Because I added the close, I also set tmpFile.setAutoRemove(false) so that the temp file was not removed automatically when closed.

I omitted the tmpFile.remove() in my post, but yes, you need to manually remove the temp file once you're done with it.