Format a Number to a specific QString format - c++

I have a question about formatting a decimal number to a certain QString format. Basically, I have an input box in my program that can take any values. I want it to translate the value in this box to the format "+05.30" (based on the value). The value will be limited to +/-99.99.
Some examples include:
.2 --> +00.02
-1.5 --> -01.50
9.9 --> +09.90
I'm thinking of using a converter like this, but it will have some obvious issues (no leading 0, no leading + sign).
QString temp = QString::number(ui.m_txtPreX1->text().toDouble(), 'f', 2);
This question had some similarities, but doesn't tie together both front and back end padding.
Convert an int to a QString with zero padding (leading zeroes)
Any ideas of how to approach this problem? Your help is appreciated! Thanks!

I don't think you can do that with any QString method alone (either number or arg). Of course you could add zeros and signs manually, but I would use the good old sprintf:
double value = 1.5;
QString text;
text.sprintf("%+06.2f", value);
Edit: Simplified the code according to alexisdm's comment.

You just have to add the sign manually:
QString("%1%2").arg(x < 0 ? '-' : '+').arg(qFabs(x),5,'f',2,'0');
Edit: The worst thing is that there is actually an internal function, QLocalePrivate:doubleToString that supports the forced sign and the padding at both end as the same time but it is only used with these options in QString::sprintf, and not:
QTextStream and its << operator, which can force the sign to show, but not the width or
QString::arg, which can force the width but not the sign.
But for QTextStream that might be a bug.

Related

QLineEdit doubleValidator starting with point

I have a UI with a QLineEdit which only accepts float/double values with the help of a QDoubleValidator.
It only accepts values if I enter a leading number like: 0.234. But I'd prefer to be able to enter values directly without a leading number like .234. Unfortunately the QDoubleValidator does not accept a leading point. Is there any way to archive my goal with the help of the validator, or do I have to check every entered character myself? I'm using Qt 5.9.1 on Windows10.
QDoubleValidator* doubleValidator = new QDoubleValidator();
QLineEdit* lineEdit = new QLineEdit(frame);
lineEdit->setValidator(doubleValidator);
vbox->addWidget(lineEdit);
Unfortunately, QDoubleValidator is pretty limited, but you can use QRegExpValidator to get what you want with a regex describing a number, depending on the notation you expect.
// non-scientific floating-point numbers
QRegExp rx("[-+]?[0-9]*\\.?[0-9]+");
QRegExpValidator v(rx, 0);
QString s;
s = ".123";
v.validate(s, 0); // Returns Acceptable
This is much more extendable, and allows you to abstract it to any condition, with basic regular expression knowledge.

Output is '*' when writing a real to a string

I have a real CURRENTTIME I want to convert to a string named TIMEDIR. As TIMEDIR has to change size it is allocatable. As far as I could find out, the allocation works fine. Also, I checked that CURRENTTIME has a value.
ALLOCATE(CHARACTER(LEN=1)::TIMEDIR)
WRITE(TIMEDIR, '(F1.0)') CURRENTTIME
But
WRITE(*,*) TIMEDIR
outputs *, where it should be 0 (CURRENTTIME is 0.0000000). I have no clue what the problem is.
You're writing the output as a floating point number. Floating point numbers always have a decimal point or an exponent to differentiate them from integers. Thus the narrowest output of a float possible is 0., i.e. 2 characters, and a format of F1.0 will always result in a "*" being printed as the field width is insufficient for what is being written.
Ian Bush's answer says what you need to know: output for a real value using the F edit descriptor requires a field width of at least 2. I'll elaborate a bit on some other aspects.
You mention
As TIMEDIR has to change size it is allocatable
but in the code fragment we see
WRITE(TIMEDIR, '(F1.0)') CURRENTTIME
This suggests a little misunderstanding. [It may be that there's no confusion, but I'll labour the point for the benefit of any other reader coming to the question.]
When an output format looks like Fw.d for w greater than zero the width of the output field is always w. This "always" means: whatever the value of the corresponding variable, the effect of the write statement above on TIMEDIR is to have a single character non-blank.
Now, as in that other answer, 2 is the minimum field width for output of a real value[1]. As with all other numeric output formatting, if the field isn't wide enough for the corresponding value the field consists entirely of *s. F1.0 will always result in output *. If you want output 0. (or 0,)[2] you'll need F2.0.
Coming back to the "varying size of TIMEDIR", output format F2.0 is (possibly) sufficient for non-negative values of CURRENTTIME less than 10, but for negative values or values not less than 10 it isn't. It may well be that this is where F0.d comes in. It's only with this form of the F edit descriptor that the width of the field depends on the output value. That's probably an answer to another question, though.
Finally, as you mention
I have to find out how to make "0" out of "0."
I'll point out that you're looking at having to do some additional logic, such as mentioned elsewhere.
1 And 2 may not be sufficient, even for a zero value: print '(SP,F2.0)', 0.
2 The choice of 0. and 0, depends on the decimal mode: print '(DC,F2.0,DP,F2.0)', 0., 0.

QLineEdit with no decimal point

I want the QLineEdit to accept only numbers without any decimal.e.g it should accept '456' but not '456.3434'.i.e. it should not allow decimal at all. Can anybody give some pointers that how can i do that.
I tried to use QIntValidator, but it still allows to enter decimal point, and when i convert the text from QLinEdit it returns zero (as it documentation says, if the conversion fails it will return zero).
I also tried to use QRegExpValidator( QRegExp("[0-9]"), but it allows only one number. There is no limit for the maximum number, how do i specify the QRegExp with minimum as 0 and maximum as undefined, if QRegExpValidator is the only way to achieve it ?
Thank you
You might try the following validator:
QLineEdit le;
le.setValidator(new QRegExpValidator(QRegExp("[0-9]+")));
le.show();
UPDATE
To allow input in exponential form you can try this:
le.setValidator(new QRegExpValidator( QRegExp("[0-9]+e[0-9]+")));

Incorrect conversion when decimal point embedded in VT_BSTR and German locale used

I have a piece of code(c++) that is writing some floating point values to excel like this:
...
values[ position ].bstrVal = formattedValue;
values[ position ].vt = VT_BSTR;
...
as you can see those floating point values are stored in the form of string and the decimal point is formatted in different ways, for example:
"110.000000", "20.11" etc. (this example is for English locale)
Now it works perfectly when English locale is used. However when I switch to German locale in the Control Panel the decimal point is changed to "," (and that's fine) but after passing those localized strings to Excel they are not correctly converted. For example in case of writing "110,000000" I'm getting 100 millions in excel. Other values like "20,11" stay as a text.
The only way to fix this is to overwrite the decimal point with "." in my program before writing to Excel. Any ideas why the conversion is not locale-aware when using VT_BSTR?
I should also add that I tried to switch the locale in my program from default one to German - still no luck.
Thank you in advance
It is never a good idea to let Excel guess at the value type. Do not use VT_BSTR, a currency value should be of variant type VT_CY. Assign the cyVal member with the value. It is an 8 byte integer value (int64 member of type LONGLONG), the currency amount multiplied by 10,000. Ten thousand :)

How can I left-justify numerical output in fortran?

I am writing some simple output in fortran, but I want whitespace delimiters. If use the following statement, however:
format(A20,ES18.8,A12,ES18.8)
I get output like this:
p001t0000 3.49141273E+01obsgp_oden 1.00000000E+00
I would prefer this:
p001t0000 3.49141273E+01 obsgp_oden 1.00000000E+00
I tried using negative values for width (like in Python) but no dice. So, is there a way to left-justify the numbers?
Many thanks in advance!
There's not a particularly beautiful way. However, using an internal WRITE statement to convert the number to a text string (formerly done with an ENCODE statement), and then manipulating the text may do what you need.
Quoting http://rsusu1.rnd.runnet.ru/develop/fortran/prof77/node168.html
An internal file WRITE is typically
used to convert a numerical value to a
character string by using a suitable
format specification, for example:
CHARACTER*8 CVAL
RVALUE = 98.6
WRITE(CVAL, '(SP, F7.2)') RVALUE
The WRITE statement will fill the
character variable CVAL with the
characters ' +98.60 ' (note that there
is one blank at each end of the
number, the first because the number
is right-justified in the field of 7
characters, the second because the
record is padded out to the declared
length of 8 characters).
Once a number has been turned into a
character-string it can be processed
further in the various ways described
in section 7. This makes it possible,
for example, to write numbers
left-justified in a field, ...
This is easier with Fortran 95, but still not trivial. Write the number or other item to a string with a write statement (as in the first answer). Then use the Fortran 95 intrinsic "ADJUSTL" to left adjust the non-blank characters of the string.
And really un-elegant is my method (I program like a cave woman), after writing the simple Fortran write format (which is not LJ), I use a combination of Excel (csv) and ultraedit to remove the spaces effectively getting the desired LJ followed directly by commas (which I need for my specific import format to another software). BF
If what you really want is whitespace between output fields rather than left-justified numbers to leave whitespace you could simply use the X edit descriptor. For example
format(A20,4X,ES18.8,4X,A12,4X,ES18.8)
will insert 4 spaces between each field and the next. Note that the standard requires 1X for one space, some of the current compilers accept the non-standard X too.
!for left-justified float with 1 decimal.. the number to the right of the decimal is how many decimals are required. Write rounds to the desired decimal space automatically, rather than truncating.
write(*, ['(f0.1)']) RValue !or
write(*, '(f0.1)') RValue
!for left-justified integers..
write(*, ['(i0)']) intValue !or
write(*, '(i0)') RValue
*after feedback from Vladimir, retesting proved the command works with or without the array brackets