QString::number() 'f' format without trailing zeros - c++

I want to convert number to QString with 3 significant digits.
QString::number(myNumber,'f',3);
does the job but remains trailing zeros. How to use it without them.
Also I've tried 'g' and which shouldn't remain those zeros:
QString::number(myNumber,'g',3);
but for example 472.76 is converted to 473. That surprised me. Why is it so with 'g' option?
However I am interested in 'f' format. So the main question is how to do it with 'f' without trailing zeros?
Input -> Desired output
472.76 -> 472.76
0.0766861 -> 0.077
180.00001 -> 180

I'm almost embarrassed to post this but it works:
QString toString( qreal num )
{
QString str = QString::number( num, 'f', 3 );
str.remove( QRegExp("0+$") ); // Remove any number of trailing 0's
str.remove( QRegExp("\\.$") ); // If the last character is just a '.' then remove it
return str;
}
If you're really concerned about the performance using this method you may want to come up with a different solution.

QString::number(myNumber,'g',3);
Will limit the conversion to the significant digits. You'll most always have 3 numbers.
472.76 => 472
4.7276 => 4.72
Try using the formatted printing functions like QString::sprintf. This should give you more control.
QString numStr;
numStr.sprintf("f.3f", myNumber);

If you insist to have the precision after the decimal point you have to use 'f'. Here is an option to remove the trailing zeors with better performance than the Regex using only QString builtins:
QString str = QString::number(myNumber,'f',3);
while(str.back() =='0')
{
str.chop(1);
}
if(str.back() =='.')
{
str.chop(1);
}
This works because the f option guarantees to put out the defined digits.
It's about 50% faster than C sprintf and 40% faster than QString::sprintf from the other answer.

QString str;
str.setNum(myNumber, 'f', 3);
This will do what you need, I tested it. Strangely, "number" behaves differently than "setNum".

How about this. It is maybe more performant than the variant with regular expressions.
The mynumber() function takes a new format char 'h', which does the job.
QString mynumber(qreal p_number, char p_format, int p_precision)
{
if(p_format=='h')
{
//like 'f' but removes trailing zeros and the '.' evtl
QString res=QString::number(p_number,'f',p_precision);
int countTrailingToRemove=0;
for(QString::const_reverse_iterator it=res.crbegin();it!=res.crend();it++)
{
if(*it=='0') countTrailingToRemove++;
else
{
if(*it=='.') countTrailingToRemove++;
break;
}
}
return res.mid(0,res.length()-countTrailingToRemove);
}
return QString::number(p_number,p_format,p_precision);
}

Related

Best way to remove white spaces from std::string

I have loaded a text file content to a std::string. And I want to remove the whitespaces from the loaded string.
Which below method need to be used for better performance?
Which below method can be a best practice.?
Else any better way is there to achieve this?
Method 1:
Scan the string using string.find() in a loop statement and remove whitespace using string.erase();
Method 2:
Scan the string using string.find() in a loop statement and copy the non whitespace characters to a new string() variable using string.append();
Method 3:
Scan the string using string.find() in a loop statement and copy the non whitespace characters to a new string(size_t n, char c) variable using string.replace();
Method 4:
Allocate a char* (using malloc[size of the source string])
Scan the string using string.find() in a loop statement and copy the non whitespace characters to the char* variable using strcpy and then strcat();
finally copy the char* to a new string
free char*
Edit: upgraded to locale-aware trait. Thanks user657267 !
Standards algorithms are neat !
s.erase(std::remove_if(
begin(s), end(s),
[l = std::locale{}](auto ch) { return std::isspace(ch, l); }
), end(s));
Live on Coliru
That was for in-place modification, if you need to keep the original string however :
std::string s2;
s2.reserve(s.size());
std::remove_copy_if(
begin(s), end(s),
std::back_inserter(s2),
[l = std::locale{}](auto ch) { return std::isspace(ch, l); }
);
Live on Coliru
IMHO, best performance you can get with method 2, but before appending you need to call std::string::reserve method to set capacity of new string to the size of initial string. This needed to prevent unnecessary reallocations, when appending.
For readability I would go with the boost string algorithm library
#include <boost/algorithm/string.hpp>
std::string str1="Hello Dolly, Hello World!"
boost::erase_all(str1, " ");
EDIT:
Example for all whitespace characters:
std::string str1="Hello Dolly,\n Hello\t World!\t";
boost::find_format_all(str1, boost::token_finder(::isspace), boost::const_formatter(""));
EDIT2:
I ran some benchmarks to see how this method compares with Quentin's answer. I ran 100 samples using both the locale aware and non locale aware version of isspace. The average times in micro seconds were:
| method | avg. time (μs) |
|-----------------------------------|----------------|
| boost::find_format_all w/locale | 2.02429 |
| boost::find_format_all w/o locale | 0.578105588 |
| std::remove_if w/locale | 1.197737742 |
| std::remove_if w/o locale | 0.190661227 |
It is not clear what exactly do you mean by "remove white spaces" - does it intend to make text unreadable and break source code, or do you mean "any excess whitespace"?
Since there was one answer that suggested a third party library, I will go in with a method from Qt, which will trim out only "excess whitespace":
QString s("Test\n new line, multiple spacebars \t tab!");
qDebug() << s;
qDebug() << s.simplified();
Output:
"Test
new line, multiple spacebars tab!"
"Test new line, multiple spacebars tab!"
Most of the other answers focus on removing all spacebars, but strictly speaking, there are other characters which classify as whitespace such as tab or new line.
Looking at the code for the simplified() method, I'd say it is fairly efficient:
QString QString::simplified() const
{
if (d->size == 0)
return *this;
QString result(d->size, Qt::Uninitialized);
const QChar *from = (const QChar*) d->data;
const QChar *fromend = (const QChar*) from+d->size;
int outc=0;
QChar *to = (QChar*) result.d->data;
for (;;) {
while (from!=fromend && from->isSpace())
from++;
while (from!=fromend && !from->isSpace())
to[outc++] = *from++;
if (from!=fromend)
to[outc++] = QLatin1Char(' ');
else
break;
}
if (outc > 0 && to[outc-1] == QLatin1Char(' '))
outc--;
result.truncate(outc);
return result;
}
The new string is preallocated without initialization, so both any initialization and any reallocations are avoided, then similarly to method 2 (keep in mind appending without reserving space will result in many and slow reallocations), only the useful data is copied to the result string, and in the end, it is trimmed shorter to remove any wasted memory.
You could follow this logic to implement it efficiently for std::string
Taken directly from the Qt source code.
Method 5: Cover all edge cases (including the current locale) with the library, and make adjustments if and only if profiling shows it to be an issue.
#include <algorithm>
#include <functional>
#include <iostream>
#include <locale>
#include <string>
template<typename CharT, typename Traits, typename Allocator>
std::basic_string<CharT, Traits, Allocator>
strip_whitespace(std::basic_string<CharT, Traits, Allocator> str)
{
str.erase(
remove_if(str.begin(), str.end(), bind(
std::isspace<CharT>, std::placeholders::_1, std::locale{}
)),
str.end()
);
return str;
}
int main()
{
std::string str{"A string with \n whitespace"};
std::cout << str << '\n' << strip_whitespace(str) << '\n';
}
For performance it would be better to read the string one platform word at a time (8 bytes on 64-bit platforms), then extract each character from the register read, test it for whitespace and if it is not a whitespace, add it to the platform word wide register to be written next. When the register to be written is full (as many characters are stored as can fit into the register), write it to the output buffer allocated in advance. Character-by-character scan is 8 times slower for single-byte character strings.
Finally, the tail of the string may contain less characters than would occupy a full platform word. A counter is needed then to know how many characters are in the last platform word processed.

How do I remove only the first character of a string that is not a digit? (MFC, C++)

I want to remove only the first character in a string that is NOT a digit. The first character can be anything from ‘A’ to ‘Z’ or it may be a special character like ‘&’ or ‘#’. This legacy code is written in MFC. I've looked at the CString class but cannot figure out how to make this work.
I have strings that may look like any of the following:
J22008943452GF or 22008943452GF or K33423333333IF or 23000526987IF or #12000895236GF. You get the idea by now.
My dilemma is I need to remove the character in the first position of all the strings, but not the strings that starts with a digit. For the strings that begin with a digit, I need to leave them alone. Also, none of the other characters in the string should not be altered. For example the ‘G’, ‘I’ or ‘F’ in the later part of the string should not be changed. The length of the string will always be 13 or 14 digits.
Here is what I have so far.
CString GAbsMeterCalibration::TrimMeterSNString (CString meterSN)
{
meterSN.MakeUpper();
CString TrimmedMeterSNString = meterSN;
int strlength = strlen(TrimmedMeterSNString);
if (strlength == 13)
{
// Check the first character anyway, even though it’s
// probably okay. If it is a digit, life’s good.
// Return unaltered TrimmedMeterSNString;
}
if (strlength == 14))
{
//Check the first character, it’s probably going
// to be wrong and is a character, not a digit.
// if I find a char in the first postion of the
// string, delete it and shift everything to the
// left. Make this my new TrimmedMeterSNString
// return altered TrimmedMeterSNString;
}
}
The string lengths are checked and validated before the calls.
From my investigations, I’ve found that MFC does not have a regular expression
class. Nor does it have the substring methods.
How about:
CString GAbsMeterCalibration::TrimMeterSNString (CString meterSN)
{
meterSN.MakeUpper();
CString TrimmedMeterSNString = meterSN;
int strlength = strlen(TrimmedMeterSNString);
if (std::isdigit(TrimmedMeterSNString.GetAt(0)) )
{
// Check the first character anyway, even though it’s
// probably okay. If it is a digit, life’s good.
// Return unaltered TrimmedMeterSNString;
}
}
From what I understand, you want to remove the first letter if it is not a digit. So you may make this function simpler:
CString GAbsMeterCalibration::TrimMeterSNString(CString meterSN)
{
meterSN.MakeUpper();
int length = meterSN.GetLength();
// just check the first character is always a digit else remove it
if (length > 0 && unsigned(meterSN[0] - TCHAR('0')) > unsigned('9'))
{
return meterSN.Right(length - 1);
}
return meterSN;
}
I am not using function isdigit instead of the conditional trick with unsigned because CString uses TCHAR which can be either char or wchar_t.
The solution is fairly straight forward:
CString GAbsMeterCalibration::TrimMeterSNString(CString meterSN) {
meterSN.MakeUpper();
return _istdigit(meterSN.GetAt(0)) ? meterSN :
meterSN.Mid(1);
}
The implementation can be compiled for both ANSI and Unicode project settings by using _istdigit. This is required since you are using CString, which stores either MBCS or Unicode character strings. The desired substring is extracted using CStringT::Mid.
(Note that CString is a typedef for a specific CStringT template instantiation, depending on your project settings.)
CString test="12355adaddfca";
if((test.GetAt(0)>=48)&&(test.GetAt(0)<=57))
{
//48 and 57 are ascii values of 0&9, hence this is a digit
//do your stuff
//CString::GetBuffer may help here??
}
else
{
//it is not a digit, do your stuff
}
Compare the ascii value of the first position in the string and you know if it's a digit or not..
I don't know if you've tried this, but, it should work.
CString str = _T("#12000895236GF");
// check string to see if it starts with digit.
CString result = str.SpanIncluding(_T("0123456789"));
// if result is empty, string does not start with a number
// and we can remove the first character. Otherwise, string
// remains intact.
if (result.IsEmpty())
str = str.Mid(1);
Seems a little easier than what's been proposed.

get atof to continue converting a string to a number after the first non valid ch in a string

i'd like to know if there a way to get atof continue converting to number even if there are non valid charcters in the way
for example let say i have string "444-3-3-33"
i want to covert it to a double a=4443333
(and keep the string as it was)
happy to get any suggestions or an alternative way
thanks!
I can't take credit for this solution, though it's a good one, see this SO post. For those too lazy to skip over, the author recommends using a locale to treat all non-numeric digits as whitespace. It might be overkill for your solution but the idea is easily adaptable. Instead of all non-numeric, you could just use "-" as your whitespace. Here's his code, not mine. Please, if you like this give him the upvote.
struct digits_only: std::ctype<char>
{
digits_only(): std::ctype<char>(get_table()) {}
static std::ctype_base::mask const* get_table()
{
static std::vector<std::ctype_base::mask>
rc(std::ctype<char>::table_size,std::ctype_base::space);
std::fill(&rc['0'], &rc['9'], std::ctype_base::digit);
return &rc[0];
}
};
bool in_range(int lower, int upper, std::string const &input) {
std::istringstream buffer(input);
buffer.imbue(std::locale(std::locale(), new digits_only()));
int n;
while (buffer>>n)
if (n < lower || upper < n)
return false;
return true;
}
Then just remove the whitespace and pass the string to atof.
Both of the following strip out non-digits for me
bool no_digit(char ch) {return !std::isdigit(ch);}
std::string read_number(const std::string& input)
{
std::string result;
std::remove_copy_if( input.begin()
, input.end()
, std::back_inserter(result)
, &no_digit);
return result;
}
std::string read_number(std::istream& is)
{
std::string result;
for(;;) {
while(is.good() && !std::isdigit(is.peek()))
is.get();
if(!is.good())
return result;
result += is.get();
}
assert(false);
}
You can then read number using string streams:
std::istringstream iss(read_number("444-3-3-33");
int i;
if( !(iss>>i) ) throw "something went wrong!";
std::cout << i << '\n';
I would recommend sscanf
[edit]
upon further review, it would seem that you'll have to use strstr as sscanf could have an issue with the embedded '-'
further, the page should give you a good start on finding (and removing) your '-' char's
[/edit]
copy the 'string number' to a local buffer(a std::string), then strip out the accepted chars from the number(compressing the string, as to not leave blank space, thus using std::string.replace), then call atof on std::string.c_str. alternatly you can use c strings, but then this wouldn't be C++.
alternatively, create a custom version of atof your self, using the source from say stdlibc or basic math.

How to convert int to QString?

Is there a QString function which takes an int and outputs it as a QString?
Use QString::number():
int i = 42;
QString s = QString::number(i);
And if you want to put it into string within some text context, forget about + operator.
Simply do:
// Qt 5 + C++11
auto i = 13;
auto printable = QStringLiteral("My magic number is %1. That's all!").arg(i);
// Qt 5
int i = 13;
QString printable = QStringLiteral("My magic number is %1. That's all!").arg(i);
// Qt 4
int i = 13;
QString printable = QString::fromLatin1("My magic number is %1. That's all!").arg(i);
Moreover to convert whatever you want, you can use QVariant.
For an int to a QString you get:
QVariant(3).toString();
A float to a string or a string to a float:
QVariant(3.2).toString();
QVariant("5.2").toFloat();
Yet another option is to use QTextStream and the << operator in much the same way as you would use cout in C++:
QPoint point(5,1);
QString str;
QTextStream(&str) << "Mouse click: (" << point.x() << ", " << point.y() << ").";
// OUTPUT:
// Mouse click: (5, 1).
Because operator <<() has been overloaded, you can use it for multiple types, not just int. QString::arg() is overloaded, for example arg(int a1, int a2), but there is no arg(int a1, QString a2), so using QTextStream() and operator << is convenient when formatting longer strings with mixed types.
Caution: You might be tempted to use the sprintf() facility to mimic C style printf() statements, but it is recommended to use QTextStream or arg() because they support Unicode strings.
I always use QString::setNum().
int i = 10;
double d = 10.75;
QString str;
str.setNum(i);
str.setNum(d);
setNum() is overloaded in many ways. See QString class reference.
A more advanced way other than the answer of Georg Fritzsche:
QString QString::arg ( int a, int fieldWidth = 0, int base = 10, const QChar & fillChar = QLatin1Char( ' ' ) ) const
Get the documentation and an example here.
If you need locale-aware number formatting, use QLocale::toString instead.
Just for completeness, you can use the standard library and do:
QString qstr = QString::fromStdString(std::to_string(42));
QLocale has a handy way of converting numbers.  It's not much more typing than the accepted answer, but is more useful in the case of floats; so I like to do both this way.  Here's for an int:
int i = 42;
QString s = QLocale().toString(i);
and here's for a float:
float f=42.5;
QString s = QLocale().toString(f, 1);
the last argument is the number of decimal places.  You can also insert a char format argument such as 'f' or 'e' for the second parameter. The advantage of this, is if your program is then run in a locale where a comma is used as a decimal "point", it will automatically print it that way.  It's not included in something like <QCoreApplication>, so you'll have to do an #include <QLocale> somewhere, of course.  It really comes into its own in formatting currency strings.
It has the slight performance downside of requiring the creation and deletion of an object during the evaluation, but were performance an issue, you could just allocate it once, and use it repeatedly.
You could write:
QString s = QString::number(42.5, 'f', 1);
but according to the help "Unlike QLocale::toString(), this function does not honor the user's locale settings."

How to print '\n' instead of a newline?

I am writing a program that uses prints a hex dump of its input. However, I'm running into problems when newlines, tabs, etc are passed in and destroying my output formatting.
How can I use printf (or cout I guess) to print '\n' instead of printing an actual newline? Do I just need to do some manual parsing for this?
EDIT: I'm receiving my data dynamically, it's not just the \n that I'm corned about, but rather all symbols. For example, this is my printf statement:
printf("%c", theChar);
How can I make this print \n when a newline is passed in as theChar but still make it print normal text when theChar is a valid printable character?
Print "\\n" – "\\" produces "\" and then "n" is recognized as an ordinary symbol. For more information see here.
The function printchar() below will print some characters as "special", and print the octal code for characters out of range (a la Emacs), but print normal characters otherwise. I also took the liberty of having '\n' print a real '\n' after it to make your output more readable. Also note that I use an int in the loop in main just to be able to iterate over the whole range of unsigned char. In your usage you would likely just have an unsigned char that you read from your dataset.
#include <stdio.h>
static void printchar(unsigned char theChar) {
switch (theChar) {
case '\n':
printf("\\n\n");
break;
case '\r':
printf("\\r");
break;
case '\t':
printf("\\t");
break;
default:
if ((theChar < 0x20) || (theChar > 0x7f)) {
printf("\\%03o", (unsigned char)theChar);
} else {
printf("%c", theChar);
}
break;
}
}
int main(int argc, char** argv) {
int theChar;
(void)argc;
(void)argv;
for (theChar = 0x00; theChar <= 0xff; theChar++) {
printchar((unsigned char)theChar);
}
printf("\n");
}
Just use "\\n" (two slashes)
You can escape the backslash to make it print just a normal backslash: "\\n".
Edit: Yes you'll have to do some manual parsing. However the code to do so, would just be a search and replace.
If you want to make sure that you don't print any non-printable characters, then you can use the functions in ctype.h like isprint:
if( isprint( theChar ) )
printf( "%c", theChar )
else
switch( theChar )
{
case '\n':
printf( "\\n" );
break;
... repeat for other interesting control characters ...
default:
printf( "\\0%hho", theChar ); // print octal representation of character.
break;
}
printf("\\n");
In addition to the examples provided by other people, you should look at the character classification functions like isprint() and iscntrl(). Those can be used to detect which characters are or aren't printable without having to hardcode hex values from an ascii table.
In C/C++, the '\' character is reserved as the escape character. So whenever you want to actually print a '\', you must enter '\'. So to print the actual '\n' value you would print the following:
printf("\\n");
Just use String::replace to replace the offending characters before you call printf.
You could wrap the printf to do something like this:
void printfNeat(char* str)
{
string tidyString(str);
tidyString.replace("\n", "\\n");
printf(tidyString);
}
...and just add extra replace statements to rid yourself of other unwanted characters.
[Edit] or if you want to use arguments, try this:
void printfNeat(char* str, ...)
{
va_list argList;
va_start(argList, msg);
string tidyString(str);
tidyString.replace("\n", "\\n");
vprintf(tidyString, argList);
va_end(argList);
}
As of C++11 you can also use raw strings
std::printf(R"(\n)");
everything inside the R"( and )" will be printed literally. escape sequences will not be processed.
There are three solutions for this question:
Solution 1:
Every Symbol, Number, Alphabet has it's own ASCII value. The ASCII value of '\' as 92 and 'n' as 110. The immediate values(Numbers (ASCII)) are stored onto two integer variables. While printing, the format specifier %c (Character), is used.
void main() {
int i=92, j=110;
clrscr();
printf("%c%c", i, j);
getch();
}
Try it out in your C programming software...
Solution 2:
The programs works. But I think this one isn't fair...
At the output screen, type the input as \n...
you will get another \n..
void main() {
char a[10];
gets(a);
printf("\n\n\n\n");
puts(a);
getch();
}
Try out the programs
Solution 3:
Already said above use \n