Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Re: converting a string containing a comma to a number

117 views
Skip to first unread message

Lynn McGuire

unread,
Nov 9, 2017, 9:10:36 PM11/9/17
to
On 11/9/2017 8:07 PM, Lynn McGuire wrote:
> Is there a standard way to convert a string containing a comma to a
> number ?  atof and strtod do not work with the comma.
>
> Thanks,
> Lynn

A string such as 4,800.1 or 3,334.5e9.

Thanks,
Lynn

Lew Pitcher

unread,
Nov 9, 2017, 10:17:53 PM11/9/17
to
Stefan Ram wrote:

> Lynn McGuire <lynnmc...@gmail.com> writes:
>>A string such as 4,800.1 or 3,334.5e9.
>
> #include <iostream>
> #include <ostream>
> #include <string>

Thanks for the C++ example. but, do you have anything in C?
--
Lew Pitcher
"In Skills, We Trust"
PGP public key available upon request

Alain Ketterlin

unread,
Nov 10, 2017, 6:39:00 AM11/10/17
to
Any of atof, strtod, sscanf will happily convert this, *provided* the
locale is setup correctly. Check setlocale (std::setlocale), especially
the LC_NUMERIC category.

See also
https://stackoverflow.com/questions/28470656/convert-string-with-thousands-and-decimal-separator-into-double

-- Alain.

Mr Flibble

unread,
Nov 10, 2017, 9:06:26 AM11/10/17
to
On 10/11/2017 02:52, Stefan Ram wrote:
> Lynn McGuire <lynnmc...@gmail.com> writes:
>> A string such as 4,800.1 or 3,334.5e9.
>
> #include <iostream>
> #include <ostream>
> #include <string>
>
> using namespace ::std::literals;
>
> /* This definition of "replace" is a stub!
> The implementation is left as an exercise. */
>
> static ::std::string replace
> ( ::std::string const & source,
> ::std::string const &, ::std::string const & )
> { ::std::string s { source };
> s.replace( 1, 1, ""s );
> return s; }

Your use of the namespace scoping operator is egregious; ::std is
totally unnecessary. Your solution is also non-optimal as it
unnecessarily passes by reference:

std::string replace(std::string source, const std::string& a, const
std::string& b)
{
source.replace(...);
return source;
}

/Flibble

Scott Lurndal

unread,
Nov 10, 2017, 9:16:15 AM11/10/17
to
r...@zedat.fu-berlin.de (Stefan Ram) writes:
> Distribution through any means other than regular usenet
>
> channels is forbidden. It is forbidden to publish this
>
> article in the world wide web. It is forbidden to change
>
> URIs of this article into links. It is forbidden to remove
>
> this notice or to transfer the body without this notice.
>X-No-Archive: Yes
>Archive: no
>X-No-Archive-Readme: "X-No-Archive" is only set, because this prevents some
>
> services to mirror the article via the web (HTTP). But Stefan Ram
>
> hereby allows to keep this article within a Usenet archive server
>
> with only NNTP access without any time limitation.
>X-No-Html: yes
>Content-Language: en
>X-Received-Body-CRC: 4148849574
>X-Received-Bytes: 1816
>
>Alain Ketterlin <al...@universite-de-strasbourg.fr.invalid> writes:
>>Any of atof, strtod, sscanf will happily convert this, *provided* the
>>locale is setup correctly.
>
> IIRC, An implementation of C is not required to support
> other locales than the "C" locale, so any code based on
> any other locale would not be portable.
>

That would seem to be a total non-sequitor.

Every POSIX implementation supports it. If windows doesn't,
then switch to posix.

James R. Kuyper

unread,
Nov 10, 2017, 9:31:18 AM11/10/17
to
On 2017-11-10 06:38, Alain Ketterlin wrote:
> Lynn McGuire <lynnmc...@gmail.com> writes:
>
>> On 11/9/2017 8:07 PM, Lynn McGuire wrote:
>>> Is there a standard way to convert a string containing a comma to a
>>> number ?  atof and strtod do not work with the comma.
>>>
>>> Thanks,
>>> Lynn
>>
>> A string such as 4,800.1 or 3,334.5e9.
>
> Any of atof, strtod, sscanf will happily convert this, *provided* the
> locale is setup correctly. Check setlocale (std::setlocale), especially
> the LC_NUMERIC category.

The C standard provides an official definition of the "decimal-point
character", explicitly identifying it as locale-specific, and frequently
uses that term when describing the behavior of the functions which
convert between floating point numbers and their representations as
strings. In particular, strtod() recognizes

"a nonempty sequence of decimal digits optionally containing a
decimal-point characters, then an optional exponent..." (7.22.1.3p3).

However, none of the other members of struct lconv are mentioned
anywhere in the standard other than the part describing <locale.h>. For
none of those members is there any function in the C standard library
whose defined behavior requires it to pay attention to the value of that
member in the current locale. The decimal-point character is the only
member of that struct for which there's a corresponding item listed in
section J.4, which summarizes locale-specific behavior. It is apparently
up to the user to write code whose behavior depends upon those values.

Note, in particular, that the description of strtod() above makes no
mention of the thousands_sep or grouping members of struct lconv. The
behavior of atof() and sscanf() are both defined in terms of calls to
strtod(), so the same is true of them.

> See also
> https://stackoverflow.com/questions/28470656/convert-string-with-thousands-and-decimal-separator-into-double

C++ differs from C in that there are C++ standard library routines that
do have behavior that depend upon values of thousands_sep and grouping
in the currently imbued locale, and that link shows how to take
advantage of that fact. Note, in particular, that even in C++,
std::strtod(), std::atof(), and std::sscanf() are NOT examples of this.
Their behavior is the same as the C standard library versions of those
routines in this regard.

Richard

unread,
Nov 10, 2017, 12:55:01 PM11/10/17
to
[Please do not mail me a copy of your followup]

Lew Pitcher <lew.p...@digitalfreehold.ca> spake the secret code
<ou35oo$2tf$1...@dont-email.me> thusly:

>Stefan Ram wrote:
>
>> Lynn McGuire <lynnmc...@gmail.com> writes:
>>>A string such as 4,800.1 or 3,334.5e9.
>>
>> #include <iostream>
>> #include <ostream>
>> #include <string>
>
>Thanks for the C++ example. but, do you have anything in C?

If you want a C example, why are you asking in a C++ newsgroup?

Followups redirected back to comp.lang.c++
--
"The Direct3D Graphics Pipeline" free book <http://tinyurl.com/d3d-pipeline>
The Terminals Wiki <http://terminals-wiki.org>
The Computer Graphics Museum <http://computergraphicsmuseum.org>
Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com>

James R. Kuyper

unread,
Nov 10, 2017, 1:14:46 PM11/10/17
to
On 2017-11-10 12:54, Richard wrote:
> [Please do not mail me a copy of your followup]
>
> Lew Pitcher <lew.p...@digitalfreehold.ca> spake the secret code
> <ou35oo$2tf$1...@dont-email.me> thusly:
...
>> Thanks for the C++ example. but, do you have anything in C?
>
> If you want a C example, why are you asking in a C++ newsgroup?

Because the OP (Lynn McGuire) posted to both newsgroups, presumably
because Lynn was looking for both a C and a C++ solution (possibly
hoping that a single solution might exist that will work in both languages).

> Followups redirected back to comp.lang.c++

Followups restored as originally specified.

jacobnavia

unread,
Nov 10, 2017, 3:22:41 PM11/10/17
to
void EliminateComma(char *src)
{
char *dst = src;
while (*src) {
if (*src != ',')
*dst++ = *src;
src++;
}
*dst=0;
}

Ben Bacarisse

unread,
Nov 10, 2017, 3:45:17 PM11/10/17
to
I'm just picking a pace to comment really...

jacobnavia <ja...@jacob.remcomp.fr> writes:

> Le 10/11/2017 à 03:10, Lynn McGuire a écrit :
>> On 11/9/2017 8:07 PM, Lynn McGuire wrote:
>>> Is there a standard way to convert a string containing a comma to a
>>> number ? atof and strtod do not work with the comma.
>>>
>> A string such as 4,800.1 or 3,334.5e9.
>>
>
> void EliminateComma(char *src)
> {
> char *dst = src;
> while (*src) {
> if (*src != ',')
> *dst++ = *src;
> src++;
> }
> *dst=0;
> }

Removing commas, either in place or in a copy, is probably how I'd do
this too, but it's also possible that it is not at all what is needed.
For example, the input might include other commas that have to be
preserved, or the removal of all commas allows input to be parsed which
should be treated as an error. Without knowing more about the overall
requirement it's hard to give good advice.

--
Ben.

Keith Thompson

unread,
Nov 10, 2017, 4:15:17 PM11/10/17
to
This might be a good first step *if* you don't mind modifying the
original string in place.

--
Keith Thompson (The_Other_Keith) ks...@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"

jacobnavia

unread,
Nov 10, 2017, 4:22:56 PM11/10/17
to
Le 10/11/2017 à 22:14, Keith Thompson a écrit :
> This might be a good first step*if* you don't mind modifying the
> original string in place.

If you do mind, make a copy before... not rocket sicence isn't it?

Chris Vine

unread,
Nov 10, 2017, 8:05:43 PM11/10/17
to
The simplest solution is to imbue a locale into a std::stringstream
object. Given a std::stringstream object 's',
s.imbue(std::locale("en_US")) would do what you want. You can then
input a string with a standard English numeric representation and
output a double of the required value.

This won't be particularly efficient. If efficiency is important then
a simple parser which makes the substitutions you want would be better.

Chris

Jorgen Grahn

unread,
Nov 11, 2017, 3:41:55 AM11/11/17
to
On Fri, 2017-11-10, Ben Bacarisse wrote:
> I'm just picking a pace to comment really...
>
> jacobnavia <ja...@jacob.remcomp.fr> writes:
>
>> Le 10/11/2017 à 03:10, Lynn McGuire a écrit :
>>> On 11/9/2017 8:07 PM, Lynn McGuire wrote:
>>>> Is there a standard way to convert a string containing a comma to a
>>>> number ? atof and strtod do not work with the comma.
>>>>
>>> A string such as 4,800.1 or 3,334.5e9.
>>>
>>
>> void EliminateComma(char *src)
>> {
>> char *dst = src;
>> while (*src) {
>> if (*src != ',')
>> *dst++ = *src;
>> src++;
>> }
>> *dst=0;
>> }
>
> Removing commas, either in place or in a copy, is probably how I'd do
> this too, but it's also possible that it is not at all what is needed.
> For example, the input might include other commas that have to be
> preserved, or the removal of all commas allows input to be parsed which
> should be treated as an error.

Like 33,,,34.,5,,e,9.

> Without knowing more about the overall
> requirement it's hard to give good advice.

Yes. IMHO, not looking at the concrete requirements has been the
problem with this thread all along.

My five cents: if I can define what's valid syntax myself, then I'd do
that first. If that means I cannot use strtod() and friends and
cannot get any help from the locale system, then so be it.

WRT locales, they are, to me, simplistic and problematic. For example,
the real situation with fractional numbers and people in Sweden:

1234,56 The official syntax.

1 234.56 Even better, but cannot be represented in ASCII since
the thousands separator is a half-width non-breaking
space. A full space is too much (and would make
it more than one token in any surrounding syntax).

I don't think the locales reflect this practice, so you
see thousands separators too rarely in computer output.

1234.56 Everyone recognizes this too, since it's what computers
ands pocket calculators have printed for decades.

1.23456e3 Programmers recognize any C syntax.

And so on.

/Jorgen

--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .

bartc

unread,
Nov 11, 2017, 6:58:02 AM11/11/17
to
I'm very surprised that C thinks this stuff belongs in such a low level
language, rather than in an application, or a library outside the
language itself. (And even applications have trouble with it: try adding
spaces to a credit-card number in a web-form.)

C doesn't even have numeric separators to help writing source, yet
printf is expected to display proper thousands separators depending on
locale? And here we also expect it to figure out the whether a comma is
properly a thousands separator or not, or if the comma is used correctly
in 1000,000.

Usually when such a language does input (from a text file, or from the
keyboard), then commas will separate different numbers, or a number and
non-number.

You can't reasonably have a comma separating thousands unless the string
representing the number has already isolated it. For example, it's from
an edit-box on a form. And then, as suggested, it really needs proper
validation if this is user-input.

--
bartc

Keith Thompson

unread,
Nov 11, 2017, 3:51:21 PM11/11/17
to
bartc <b...@freeuk.com> writes:
[...]
> C doesn't even have numeric separators to help writing source, yet
> printf is expected to display proper thousands separators depending on
> locale?

No, it isn't. POSIX specifies "%'d", for example, but ISO C has
no facility for handling thousands separators in input or output.
(It does let you query the current locale.)

[...]

bartc

unread,
Nov 11, 2017, 5:01:17 PM11/11/17
to
On 11/11/2017 20:50, Keith Thompson wrote:
> bartc <b...@freeuk.com> writes:
> [...]
>> C doesn't even have numeric separators to help writing source, yet
>> printf is expected to display proper thousands separators depending on
>> locale?
>
> No, it isn't. POSIX specifies "%'d", for example, but ISO C has
> no facility for handling thousands separators in input or output.
> (It does let you query the current locale.)

It works with lccwin.

But there seems a thin dividing line between C headers and POSIX ones,
which isn't exactly obvious in this list:

http://pubs.opengroup.org/onlinepubs/9699919799/idx/head.html

And if I try and compile any open source using only C standard headers,
it will likely fail.

--
bartc

Vir Campestris

unread,
Nov 12, 2017, 4:27:06 PM11/12/17
to
On 10/11/2017 14:16, Scott Lurndal wrote:
> That would seem to be a total non-sequitor.[sic]
>
> Every POSIX implementation supports it. If windows doesn't,
> then switch to posix.

That would also appear to be a non sequitur. There are many reasons for
disliking Windows, but it's had POSIX support since the first NT release
nearly 25 years ago.

Andy

Scott Lurndal

unread,
Nov 13, 2017, 9:20:54 AM11/13/17
to
as a second class fig-leaf to enable bidding on federal contracts.

James R. Kuyper

unread,
Nov 13, 2017, 11:19:18 AM11/13/17
to
Could you clarify precisely how Windows POSIX support falls short of
being first-class? It's not that I don't believe you - I'm just looking
for details.

Scott Lurndal

unread,
Nov 13, 2017, 12:39:38 PM11/13/17
to
When they did it back in the 90's, they implemented the absolute minimum
possible (IEEE 1003.1-1990). That subsystem was replaced in XP by the
Windows Services for Unix (SFU). SFU was removed from Windows 8 and Server 2012
and is not included in any modern windows release (although windows 10
has the Ubuntu subsystem in the creators edition).

Lynn McGuire

unread,
Nov 13, 2017, 4:38:26 PM11/13/17
to
On 11/11/2017 11:26 AM, Mr. Man-wai Chang wrote:
> On 10/11/2017 10:07 AM, Lynn McGuire wrote:
>> Is there a standard way to convert a string containing a comma to a
>> number ?  atof and strtod do not work with the comma.
>
> Take out the commas then use atoi()?

I did that and used atof.

double asDouble (const char * str)
{
if (str)
{
char numString [100];
memset (numString, 0, sizeof (numString));
int len = strlen (str);
char * p = numString;
for (int i = 0; i < len; i++)
{
// remove any and all commas such as "4,800.4" before calling atof
if (numString [i] != ',')
{
* p = str [i];
p++;
}
}
return atof (numString);
}
else
return 0.0;
}



double asDouble (std::string string)
{
if (string.size () > 0)
return asDouble (string.c_str ());
else
return 0.0;
}


Lynn



Keith Thompson

unread,
Nov 13, 2017, 5:45:53 PM11/13/17
to
Lynn McGuire <lynnmc...@gmail.com> writes:
> On 11/11/2017 11:26 AM, Mr. Man-wai Chang wrote:
>> On 10/11/2017 10:07 AM, Lynn McGuire wrote:
>>> Is there a standard way to convert a string containing a comma to a
>>> number ?  atof and strtod do not work with the comma.
>>
>> Take out the commas then use atoi()?
>
> I did that and used atof.
>
> double asDouble (const char * str)
> {
> if (str)
> {
> char numString [100];
> memset (numString, 0, sizeof (numString));
> int len = strlen (str);
> char * p = numString;
> for (int i = 0; i < len; i++)
> {
> // remove any and all commas such as "4,800.4" before calling atof
> if (numString [i] != ',')
> {
> * p = str [i];
> p++;
> }
> }
> return atof (numString);
> }
> else
> return 0.0;
> }
[...]

And did that work? It shouldn't, since `numString [i]` will always be a
null character.

Incidentally, atof() does no error checking.

Ralf Goertz

unread,
Nov 14, 2017, 1:54:42 AM11/14/17
to
Am Mon, 13 Nov 2017 14:45:23 -0800
schrieb Keith Thompson <ks...@mib.org>:

> Lynn McGuire <lynnmc...@gmail.com> writes:
> > On 11/11/2017 11:26 AM, Mr. Man-wai Chang wrote:
> >> On 10/11/2017 10:07 AM, Lynn McGuire wrote:
> >>> Is there a standard way to convert a string containing a comma to
> >>> a number ?  atof and strtod do not work with the comma.
> >>
> >> Take out the commas then use atoi()?
> >
> > I did that and used atof.
> >
> > double asDouble (const char * str)
> > {
> > if (str)
> > {
> > char numString [100];
> > memset (numString, 0, sizeof (numString));
> > int len = strlen (str);
> > char * p = numString;
> > for (int i = 0; i < len; i++)
> > {
> > // remove any and all commas such as "4,800.4" before calling atof
> > if (numString [i] != ',')
> > {
> > * p = str [i];
> > p++;
> > }
> > }
> > return atof (numString);
> > }
> > else
> > return 0.0;
> > }
> [...]
>
> And did that work? It shouldn't, since `numString [i]` will always
> be a null character.

That is not the problem, is it?. numString[i] gets set to str[i] but
unconditionally since the null character is not equal to ','. The
problem is that numString instead of str is queried for the existence of
commas.



Ben Bacarisse

unread,
Nov 14, 2017, 7:24:50 AM11/14/17
to
It's a problem because the function won't do what it's supposed to!
Instead, it's just an unsafe version of

double asDouble(const char *str) { return str ? atof(str) : 0; }

But the error (in effect a typo) is not a serious one in the sense that
it will show up on the very first test and can't cause dangerous
behaviour such as the code appearing to work.

I'd do something along these lines:

double asDouble(const char *str)
{
if (str) {
char str_cpy[100], *cp = str_cpy;
while (cp < str_cpy + sizeof str_cpy)
if ((*cp = *str++) == 0)
return atof(str_cpy);
else if (*cp != ',')
cp += 1;
}
return NAN;
}

I think NAN (from math.h) is a better error return on most systems (and
you can use an ifdef to to something else on implementations without a
quiet NaN) and I'd want to prevent overflow even if I knew it could not
happen in this program. That's just because code often gets re-used and
it may not always be safe.

I say "along these lines" because I'd probably use strtod and return a
NaN when strtod reports an error too, at least in some cases.

<snip>
--
Ben.

Lynn McGuire

unread,
Nov 14, 2017, 3:29:31 PM11/14/17
to
On 11/13/2017 4:45 PM, Keith Thompson wrote:
> Lynn McGuire <lynnmc...@gmail.com> writes:
>> On 11/11/2017 11:26 AM, Mr. Man-wai Chang wrote:
>>> On 10/11/2017 10:07 AM, Lynn McGuire wrote:
>>>> Is there a standard way to convert a string containing a comma to a
>>>> number ?  atof and strtod do not work with the comma.
>>>
>>> Take out the commas then use atoi()?
>>
>> I did that and used atof.
>>
>> double asDouble (const char * str)
>> {
>> if (str)
>> {
>> char numString [100];
>> memset (numString, 0, sizeof (numString));
>> int len = strlen (str);
>> char * p = numString;
>> for (int i = 0; i < len; i++)
>> {
>> // remove any and all commas such as "4,800.4" before calling atof
>> if (numString [i] != ',')
>> {
>> * p = str [i];
>> p++;
>> }
>> }
>> return atof (numString);
>> }
>> else
>> return 0.0;
>> }
> [...]
>
> And did that work? It shouldn't, since `numString [i]` will always be a
> null character.
>
> Incidentally, atof() does no error checking.

Nope, as you pointed out, I had a bug. Once fixed, yes, it worked fine
once I replaced all the calls to atof with asDouble.

I am ok with atof not having any error checking.

Thanks,
Lynn


0 new messages