Natural sort of filenames with numbers issue c++ - c++

I have a text file to sort, which contains the paths to the image files:
/images/calibrationImageRightCamera4.jpg
/images/calibrationImageLeftCamera1.jpg
/images/calibrationImageRightCamera5.jpg
/images/calibrationImageLeftCamera2.jpg
/images/calibrationImageLeftCamera4.jpg
/images/calibrationImageRightCamera6.jpg
/images/calibrationImageLeftCamera3.jpg
/images/calibrationImageRightCamera3.jpg
/images/calibrationImageRightCamera2.jpg
/images/calibrationImageLeftCamera5.jpg
/images/calibrationImageRightCamera1.jpg
/images/calibrationImageLeftCamera7.jpg
/images/calibrationImageLeftCamera6.jpg
/images/calibrationImageRightCamera7.jpg
I use this code to sort the file:
QFile imageListFile;
QStringList sortedImageListFile;
QString filePath;
filePath= "C:/Users/Desktop/textstream/sorted.xml";
imageListFile.setFileName(filePath);
if (!imageListFile.open(QFile::ReadOnly))
{
cout<<"Error opening file"<<endl;
}
else
{
while(!imageListFile.atEnd())
{
sortedImageListFile.append(imageListFile.readLine());
}
imageListFile.close();
}
// Sort the image file
qSort(sortedImageListFile.begin(), sortedImageListFile.end(), naturalSortCallback);
QTextStream stream(&imageListFile);
// Save sorted image in the same file
if(imageListFile.open((QIODevice::ReadWrite | QIODevice::Truncate)))
{
for(QStringList::Iterator it= sortedImageListFile.begin(); it!= sortedImageListFile.end(); ++it)
{
stream << *it;
}
}
imageListFile.close();
inline int findNumberPart(const QString &sIn)
{
QString s= "";
int i= 0;
bool isNum= false;
while(i< sIn.length())
{
if(isNum)
{
if(!sIn[i].isNumber())
break;
s += sIn[i];
}
else
{
if(sIn[i].isNumber())
s += sIn[i];
}
++i;
}
if(s == "")
return 0;
return s.toInt();
}
static bool naturalSortCallback(const QString &s1, const QString &s2)
{
int idx1= findNumberPart(s1);
int idx2= findNumberPart(s2);
return(idx1 < idx2);
}
And I get as result:
/cameraCalibrationFiles/calibrationImageLeftCamera1.jpg
/cameraCalibrationFiles/calibrationImageRightCamera1.jpg
/cameraCalibrationFiles/calibrationImageLeftCamera2.jpg
/cameraCalibrationFiles/calibrationImageRightCamera2.jpg
/cameraCalibrationFiles/calibrationImageLeftCamera3.jpg
/cameraCalibrationFiles/calibrationImageRightCamera3.jpg
/cameraCalibrationFiles/calibrationImageRightCamera4.jpg
/cameraCalibrationFiles/calibrationImageLeftCamera4.jpg
/cameraCalibrationFiles/calibrationImageLeftCamera5.jpg
/cameraCalibrationFiles/calibrationImageRightCamera5.jpg
/cameraCalibrationFiles/calibrationImageRightCamera6.jpg
/cameraCalibrationFiles/calibrationImageLeftCamera6.jpg
/cameraCalibrationFiles/calibrationImageLeftCamera7.jpg
/cameraCalibrationFiles/calibrationImageRightCamera7.jpg
The numbers at the and are sorted correctly but not the filenames. sometimes the words "Left" and "Right" are mixed. The order should look like:
..LeftCamera1.jpg
..RightCamera1.jpg
..LeftCamera2.jpg
..RightCamera2.jpg
.
.
.
Where is my mistake? Thank you for any help.

You problem is the way you are comparing the strings.
inline int findNumberPart(const QString &sIn)
Is just giving you the ending number from the string. So any string ending in 1 will come before any other string. This is why the right and left cameras file names are getting mixed together and in no particular order. What you need to do is compare the number part and if that is equal then compare the string part. If not then just compare the number part.

You should compare number part and then string part on equal number part.
inline int findStringPart(const QString &s)
{
...
return stringPart; //Left or Right
}
static bool naturalSortCallback(const QString &s1, const QString &s2)
{
int numberPart1 = findNumberPart(s1);
int numberPart2 = findNumberPart(s2);
QString stringPart1 = findStringPart(s1);
QString stringPart2 = findStringPart(s2);
if(numberPart1 == numberPart2)
return stringPart1 < stringPart2; //"Left" < "Right"
return numberPart1 < numberPart2;
}

Related

Check if two given strings are isomorphic to each other c++, not sure why it's wrong

class Solution {
public:
bool isIsomorphic(string s, string t) {
vector <int> sfreq (26,0);
vector <int> tfreq (26,0);
for (int i=0; i<s.size(); i++) {
sfreq[s[i]-'a']++;
tfreq[t[i]-'a']++;
}
if (sfreq != tfreq) {
return false;
}
return true;
}
};
Hi, this is my code in c++, I saw something similar from https://www.geeksforgeeks.org/check-if-two-given-strings-are-isomorphic-to-each-other/ but my answer shows it's wrong. Can anyone please tell me why it's wrong?
You completely misunderstood the description.
Your question suggests that any permutation of characters in input do not change answer. Also you assumed that histograms are equal.
Position of character is important. Each position in both strings creates a unique pair.
Here my code which passed:
class Solution {
public:
static bool canMapInOneDirection(std::string_view s, std::string_view t)
{
const auto n = s.size();
std::array<char, 128> mapping{};
for(size_t i = 0; i < n; ++i) {
if (mapping[s[i]] == 0) mapping[s[i]] = t[i];
else if (mapping[s[i]] != t[i]) return false;
}
return true;
}
bool isIsomorphic(string s, string t)
{
return s.size() == t.size() && canMapInOneDirection(s, t) && canMapInOneDirection(t, s);
}
};
And test cases you can use to test your code:
s
t
answear
"a"
"b"
true
"aa"
"bb"
true
"ab"
"aa"
false
"aabbcc"
"aabcbc"
false
https://godbolt.org/z/61EcTK5fq
This not a question about anagrams or directly about character frequencies. It is about pattern. It's about having a character-by-character mapping that makes one string into the other. AABC is isomorphic to XXYZ but not isomorphic to BCAA.
When we talk about Isomorphism (same form) it's often a good idea to look for a signature representation.
So instead of determining if two strings are isomorphic I've decided to define a unique signature representation and determine isomorphism if two strings map to the same signature.
I've used std::vector<char> for the signature representation such that the first character (if any) is assigned 0 the second (previously unseen) character 1 and so on.
So a string like MOON has signature {0,1,1,2} because the middle characters are the only repeats. MOON is isomorphic to BOOK but not NOON.
The advantage of such a strategy is that if many strings are to be compared to find groups of mutually isomorphic strings each string need only be converted to its signature once.
#include <iostream>
#include <string>
#include <vector>
#include <unordered_map>
std::vector<char> get_signature(const std::string& str){
std::vector<char> result;
std::unordered_map<char,char> map;
char curr{1};
for(auto cchar : str){
char& c{map[cchar]};
if(c==0){
c=curr++;
}
result.emplace_back(c-1);
}
return result;
}
int check_signature(const std::string& str, const std::vector<char>& expect ){
const auto result{get_signature(str)};
return result==expect?0:1;
}
int main() {
int errors{0};
{
const std::string str{"ABCDE"};
const std::vector<char> signat{0,1,2,3,4};
errors+=check_signature(str,signat);
}
{
const std::string str{"BABY"};
const std::vector<char> signat{0,1,0,2};
errors+=check_signature(str,signat);
}
{
const std::string str{"XXYZX"};
const std::vector<char> signat{0,0,1,2,0};
errors+=check_signature(str,signat);
}
{
const std::string str{"AABCA"};
const std::vector<char> signat{0,0,1,2,0};
errors+=check_signature(str,signat);
}
{
const std::string str{""};
const std::vector<char> signat{};
errors+=check_signature(str,signat);
}
{
const std::string str{"Z"};
const std::vector<char> signat{0};
errors+=check_signature(str,signat);
}
if(get_signature("XXYZX")!=get_signature("AABCA")){
++errors;
}
if(get_signature("MOON")==get_signature("AABCA")){
++errors;
}
if(get_signature("MOON")!=get_signature("BOOK")){
++errors;
}
if(get_signature("MOON")==get_signature("NOON")){
++errors;
}
if(errors!=0){
std::cout << "ERRORS\n";
}else{
std::cout << "SUCCESS\n";
}
return 0;
}
Expected Output: SUCCESS
Because you are missing a loop.
Note that, it still requires more corner case checking to make it fully work. The second approach properly handles all cases.
class Solution {
public:
bool isIsomorphic(string s, string t) {
vector <int> sfreq (26,0);
vector <int> tfreq (26,0);
for (int i=0; i < s.size(); i++) {
sfreq[s[i]-'a']++;
tfreq[t[i]-'a']++;
}
// character at the same index (can be different character) should have the same count.
for(int i= 0; i < s.size(); i++)
if (sfreq[s[i]-'a'] != tfreq[t[i]-'a']) return false;
return true;
}
};
But the above solution only works if there is direct index mappping between characters. Like, AAABBCA and XXXYYZX. But fails for bbbaaaba and aaabbbba. Also, no uppercase, lowercase handled. The link you shared contains the wrong implementation which is mentioned in the comment.
The solution below works as I tested.
class Solution {
public:
bool isIsomorphic(string s, string t) {
vector<int> scount(128, -1), tcount(128, -1);
for (int i = 0; i < s.size(); ++i) {
auto schar = s[i], tchar = t[i];
if (scount[schar] == -1) {
scount[schar] = tchar;
if (tcount[tchar] != -1) return false;
else tcount[tchar] = schar;
} else if (scount[schar] != tchar) return false;
}
return true;
}
};

How can I speed up parsing of large strings?

So I've made a program that reads in various config files. Some of these config files can be small, some can be semi-large (largest one is 3,844 KB).
The read in file is stored in a string (in the program below it's called sample).
I then have the program extract information from the string based on various formatting rules. This works well, the only issue is that when reading larger files it is very slow....
I was wondering if there was anything I could do to speed up the parsing or if there was an existing library that does what I need (extract string up until a delimiter & extract string string in between 2 delimiters on the same level). Any assistance would be great.
Here's my code & a sample of how it should work...
#include "stdafx.h"
#include <string>
#include <vector>
std::string ExtractStringUntilDelimiter(
std::string& original_string,
const std::string& delimiter,
const int delimiters_to_skip = 1)
{
std::string needle = "";
if (original_string.find(delimiter) != std::string::npos)
{
int total_found = 0;
auto occurance_index = static_cast<size_t>(-1);
while (total_found != delimiters_to_skip)
{
occurance_index = original_string.find(delimiter);
if (occurance_index != std::string::npos)
{
needle = original_string.substr(0, occurance_index);
total_found++;
}
else
{
break;
}
}
// Remove the found string from the original string...
original_string.erase(0, occurance_index + 1);
}
else
{
needle = original_string;
original_string.clear();
}
if (!needle.empty() && needle[0] == '\"')
{
needle = needle.substr(1);
}
if (!needle.empty() && needle[needle.length() - 1] == '\"')
{
needle.pop_back();
}
return needle;
}
void ExtractInitialDelimiter(
std::string& original_string,
const char delimiter)
{
// Remove extra new line characters
while (!original_string.empty() && original_string[0] == delimiter)
{
original_string.erase(0, 1);
}
}
void ExtractInitialAndFinalDelimiters(
std::string& original_string,
const char delimiter)
{
ExtractInitialDelimiter(original_string, delimiter);
while (!original_string.empty() && original_string[original_string.size() - 1] == delimiter)
{
original_string.erase(original_string.size() - 1, 1);
}
}
std::string ExtractStringBetweenDelimiters(
std::string& original_string,
const std::string& opening_delimiter,
const std::string& closing_delimiter)
{
const size_t first_delimiter = original_string.find(opening_delimiter);
if (first_delimiter != std::string::npos)
{
int total_open = 1;
const size_t opening_index = first_delimiter + opening_delimiter.size();
for (size_t i = opening_index; i < original_string.size(); i++)
{
// Check if we have room for opening_delimiter...
if (i + opening_delimiter.size() <= original_string.size())
{
for (size_t j = 0; j < opening_delimiter.size(); j++)
{
if (original_string[i + j] != opening_delimiter[j])
{
break;
}
else if (j == opening_delimiter.size() - 1)
{
total_open++;
}
}
}
// Check if we have room for closing_delimiter...
if (i + closing_delimiter.size() <= original_string.size())
{
for (size_t j = 0; j < closing_delimiter.size(); j++)
{
if (original_string[i + j] != closing_delimiter[j])
{
break;
}
else if (j == closing_delimiter.size() - 1)
{
total_open--;
}
}
}
if (total_open == 0)
{
// Extract result, and return it...
std::string needle = original_string.substr(opening_index, i - opening_index);
original_string.erase(first_delimiter, i + closing_delimiter.size());
// Remove new line symbols
ExtractInitialAndFinalDelimiters(needle, '\n');
ExtractInitialAndFinalDelimiters(original_string, '\n');
return needle;
}
}
}
return "";
}
int main()
{
std::string sample = "{\n"
"Line1\n"
"Line2\n"
"{\n"
"SubLine1\n"
"SubLine2\n"
"}\n"
"}";
std::string result = ExtractStringBetweenDelimiters(sample, "{", "}");
std::string LineOne = ExtractStringUntilDelimiter(result, "\n");
std::string LineTwo = ExtractStringUntilDelimiter(result, "\n");
std::string SerializedVector = ExtractStringBetweenDelimiters(result, "{", "}");
std::string SubLineOne = ExtractStringUntilDelimiter(SerializedVector, "\n");
std::string SubLineTwo = ExtractStringUntilDelimiter(SerializedVector, "\n");
// Just for testing...
printf("LineOne: %s\n", LineOne.c_str());
printf("LineTwo: %s\n", LineTwo.c_str());
printf("\tSubLineOne: %s\n", SubLineOne.c_str());
printf("\tSubLineTwo: %s\n", SubLineTwo.c_str());
system("pause");
}
Use string_view or a hand rolled one.
Don't modify the string loaded.
original_string.erase(0, occurance_index + 1);
is code smell and going to be expensive with a large original string.
If you are going to modify something, do it in one pass. Don't repeatedly delete from the front of it -- that is O(n^2). Instead, procceed along it and shove "finished" stuff into an output accumulator.
This will involve changing how your code works.
You're reading your data into a string. "Length of string" should not be a problem. So far, so good...
You're using "string.find().". That's not necessarily a bad choice.
You're using "string.erase()". That's probably the main source of your problem.
SUGGESTIONS:
Treat the original string as "read-only". Don't call erase(), don't modify it.
Personally, I'd consider reading your text into a C string (a text buffer), then parsing the text buffer, using strstr().
Here is a more efficient version of ExtractStringBetweenDelimiters. Note that this version does not mutate the original buffer. You would perform subsequent queries on the returned string.
std::string trim(std::string buffer, char what)
{
auto not_what = [&what](char ch)
{
return ch != what;
};
auto first = std::find_if(buffer.begin(), buffer.end(), not_what);
auto last = std::find_if(buffer.rbegin(), std::make_reverse_iterator(first), not_what).base();
return std::string(first, last);
}
std::string ExtractStringBetweenDelimiters(
std::string const& buffer,
const char opening_delimiter,
const char closing_delimiter)
{
std::string result;
auto first = std::find(buffer.begin(), buffer.end(), opening_delimiter);
if (first != buffer.end())
{
auto last = std::find(buffer.rbegin(), std::make_reverse_iterator(first),
closing_delimiter).base();
if(last > first)
{
result.assign(first + 1, last);
result = trim(std::move(result), '\n');
}
}
return result;
}
If you have access to string_view (c++17 for std::string_view or boost::string_view) you could return one of these from both functions for extra efficiency.
It's worth mentioning that this method of parsing a structured file is going to cause you problems down the line if any of the serialised strings contains a delimiter, such as a '{'.
In the end you'll want to write or use someone else's parser.
The boost::spirit library is a little complicated to learn, but creates very efficient parsers for this kind of thing.

QString compare with digits [duplicate]

I am reading a directories content using QDir::entryList(). The filenames within are structured like this:
index_randomNumber.png
I need them sorted by index, the way the Windows Explorer would sort the files so that I get
0_0815.png
1_4711.png
2_2063.png
...
instead of what the sorting by QDir::Name gives me:
0_0815.png
10000_6661.png
10001_7401.png
...
Is there a built-in way in Qt to achieve this and if not, what's the right place to implement it?
If you want to use QCollator to sort entries from the list of entries returned by QDir::entryList, you can sort the result with std::sort():
dir.setFilter(QDir::Files | QDir::NoSymLinks);
dir.setSorting(QDir::NoSort); // will sort manually with std::sort
auto entryList = dir.entryList();
QCollator collator;
collator.setNumericMode(true);
std::sort(
entryList.begin(),
entryList.end(),
[&](const QString &file1, const QString &file2)
{
return collator.compare(file1, file2) < 0;
});
According to The Badger's comment, QCollator can also be used directly as an argument to std::sort, replacing the lambda, so the call to std::sort becomes:
std::sort(entryList.begin(), entryList.end(), collator);
Qt didn't have natural sort implementation until Qt 5.2, see this feature request.
Since Qt 5.2 there is QCollator which allows natural sort when numeric mode is enabled.
Yes it is possible.
In order to do that you need to specify the flag LocaleAware when constructing the QDir. object. The constructor is
QDir(const QString & path, const QString & nameFilter, SortFlags sort = SortFlags( Name | IgnoreCase ), Filters filters = AllEntries)
You can also use
QDir dir;
dir.setSorting(QDir::LocaleAware);
inline int findNumberPart(const QString& sIn)
{
QString s = "";
int i = 0;
bool isNum = false;
while (i < sIn.length())
{
if (isNum)
{
if (!sIn[i].isNumber())
break;
s += sIn[i];
}
else
{
if (sIn[i].isNumber())
s += sIn[i];
}
++i;
}
if (s == "")
return 0;
return s.toInt();
}
bool naturalSortCallback(const QString& s1, const QString& s2)
{
int idx1 = findNumberPart(s1);
int idx2 = findNumberPart(s2);
return (idx1 < idx2);
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QDir dir(MYPATH);
QStringList list = dir.entryList(QDir::AllEntries | QDir::NoDotAndDotDot);
qSort(list.begin(), list.end(), naturalSortCallback);
foreach(QString s, list)
qDebug() << s << endl;
return a.exec();
}
This isn't an answer to the question as such, but some general information for the benefit of others that stumble across this trying to figure out how to "sort naturally".
First off: it's impossible. "Correct" natural sorting depends on context that — short of "true" artificial intelligence — is virtually impossible to have. For instance, if I have a bunch of file names with mixed numbers and letters, and some parts of those names happen to match [0-9a-f], is that a hexadecimal number? Is "1,500" the same as "1500", or are "1" and "500" individual numbers? Does "2019/06/07" come before or after "2019/07/06"? What about "1.21" vs. "1.5"? (Hint: the last depends on if those are decimal numbers or semantic version numbers.)
"Solving" this problem requires constraining it; deciding we're only going to handle specific cases, and anything outside of those bounds is just going to produce a "wrong" answer. (Fortunately, the OP's problem would appear to already satisfy the usual set of constraints.)
That said, I believe QCollator works generally well (again, in that it doesn't "really" work, but it succeeds within the constraints that are generally accepted). In the "own solutions" department, have a look also at qtNaturalSort, which I wrote as a Qt-API improvement over a different (not QCollator) algorithm. (Case insensitivity is not supported as of writing, but patches welcomed!) I put a whole bunch of effort into making it parse numbers "correctly", even handling numbers of arbitrary length and non-BMP digits.
Qt doesn't support natural sorting natively, but it can be quite easily implemented. For example, this can be used to sort a QStringList:
struct naturalSortCompare {
inline bool isNumber(QChar c) {
return c >= '0' && c <= '9';
}
inline bool operator() (const QString& s1, const QString& s2) {
if (s1 == "" || s2 == "") return s1 < s2;
// Move to the first difference between the strings
int startIndex = -1;
int length = s1.length() > s2.length() ? s2.length() : s1.length();
for (int i = 0; i < length; i++) {
QChar c1 = s1[i];
QChar c2 = s2[i];
if (c1 != c2) {
startIndex = i;
break;
}
}
// If the strings are the same, exit now.
if (startIndex < 0) return s1 < s2;
// Now extract the numbers, if any, from the two strings.
QString sn1;
QString sn2;
bool done1 = false;
bool done2 = false;
length = s1.length() < s2.length() ? s2.length() : s1.length();
for (int i = startIndex; i < length; i++) {
if (!done1 && i < s1.length()) {
if (isNumber(s1[i])) {
sn1 += QString(s1[i]);
} else {
done1 = true;
}
}
if (!done2 && i < s2.length()) {
if (isNumber(s2[i])) {
sn2 += QString(s2[i]);
} else {
done2 = true;
}
}
if (done1 && done2) break;
}
// If none of the strings contain a number, use a regular comparison.
if (sn1 == "" && sn2 == "") return s1 < s2;
// If one of the strings doesn't contain a number at that position,
// we put the string without number first so that, for example,
// "example.bin" is before "example1.bin"
if (sn1 == "" && sn2 != "") return true;
if (sn1 != "" && sn2 == "") return false;
return sn1.toInt() < sn2.toInt();
}
};
Then usage is simply:
std::sort(stringList.begin(), stringList.end(), naturalSortCompare());

Splitting text into a list of words with ICU

I'm working on a text tokenizer. ICU is one of very few C++ libraries that have this feature, and probably the best maintained one, so I'd like to use it.
I've found the docs about BreakIterator, but there's one problem with it: how do I leave the punctuation out?
#include "unicode/brkiter.h"
#include <QFile>
#include <vector>
std::vector<QString> listWordBoundaries(const UnicodeString& s)
{
UErrorCode status = U_ZERO_ERROR;
BreakIterator* bi = BreakIterator::createWordInstance(Locale::getUS(), status);
std::vector<QString> words;
bi->setText(s);
for (int32_t p = bi->first(), prevBoundary = 0; p != BreakIterator::DONE; prevBoundary = p, p = bi->next())
{
const auto word = s.tempSubStringBetween(prevBoundary, p);
char buffer [16384];
word.toUTF8(CheckedArrayByteSink(buffer, 16384));
words.emplace_back(QString::fromUtf8(buffer));
}
delete bi;
return words;
}
int main(int /*argc*/, char * /*argv*/ [])
{
QFile f("E:\\words.TXT");
f.open(QFile::ReadOnly);
QFile result("E:\\words.TXT");
result.open(QFile::WriteOnly);
const QByteArray strData = f.readAll();
for (const QString& word: listWordBoundaries(UnicodeString::fromUTF8(StringPiece(strData.data(), strData.size()))))
{
result.write(word.toUtf8());
result.write("\n");
}
return 0;
}
Naturally, the resulting file looks like this:
“
Come
outside
.
Best
if
we
do
not
wake
him
.
”
What I need is just the words. How can this be done?
QT library include several useful methods for check the char's properties:
QChar.
Indeed, you could create the QString variable from the buffer
and check all properties you need before to insert into the output vector.
For example:
auto token = QString::fromUtf8(buffer);
if (token.length() > 0 && token.data()[0].isPunct() == false) {
words.push_back(std::move(token));
}
With that code I can access the first character of the string and check
whether it is a punctuation mark or not.
Something more robust, I express that as function:
bool isInBlackList(const QString& str) {
const auto len = str.lenght();
if (len == 0) return true;
for(int i = 0; i < len; ++i) {
const auto&& c = str.data()[i];
if (c.isPunct() == true || c.isSpace() == true) {
return true;
}
}
return false;
}
If that function returns true, the token hasn't to be inserted into the vector.

Find a number inside a QString

I have a QString with some number inside it, for example
first_34.33string
second-23.4string // In this case number is negative
How can I extract number from the string?
EDIT:
This function seems to work, using regexp in replies:
float getNumberFromQString(const QString &xString)
{
QRegExp xRegExp("(-?\\d+(?:[\\.,]\\d+(?:e\\d+)?)?)");
xRegExp.indexIn(xString);
QStringList xList = xRegExp.capturedTexts();
if (true == xList.empty())
{
return 0.0;
}
return xList.begin()->toFloat();
}
This should work for valid numbers: QRegExp("(-?\\d+(?:[\\.,]\\d+(?:e\\d+)?)?)")
edit: sorry, messed up with the brackets, now it should work.
I would write a simple function for that:
static double extractDouble(const QString &s)
{
QString num;
foreach(QChar c, s) {
if (c.isDigit() || c == '.' || c == '-') {
num.append(c);
}
}
bool ok;
double ret = num.toDouble(&ok);
if (ok) {
return ret;
} else {
throw "Cannot extract double value";
}
}