[capi-sig] String to number conversion
M.-A. Lemburg
mal at egenix.com
Wed May 7 17:46:09 CEST 2008
On 2008-05-07 17:27, Hrvoje Niksic wrote:
> I miss a function able to convert the string representation of a
> Python primitive number (int, long, float, complex) to an actual
> number, basically the reverse of repr for numbers. The only option I
> know of that doesn't involve inspecting the individual digits is eval,
> which doesn't cut it -- besides the obvious security implications, it
> tends to be slow when used en masse. What I have in mind is something
> along the lines of:
>
>>>> read_number('1')
> 1
>>>> read_number('1.')
> 1.0
>>>> read_number('3.14')
> 3.1400000000000001
>>>> read_number('1000000000000000000')
> 1000000000000000000L
>>>> read_number('2+3j')
> (2+3j)
>>>> read_number('1e100')
> 1e+100
>>>> read_number('bla')
> Traceback (most recent call last):
> File "<stdin>", line 1, in <module>
> ValueError: invalid numeric value 'bla'
>
> A sample implementation, a variation of which I use in an in-house
> project, follows. It does inspect the string to determine its type,
> but does so in a simple C loop which is quite fast for numeric input.
> It leaves the actual conversion to the Python's API code that knows
> what it's doing. Because of that it's simple and fast, but still (to
> my knowledge) correct.
>
> PyObject *
> read_number(PyObject *str)
> {
> int isfloat = 0, iscomplex = 0;
>
> /* First, intuit the type based on characters that appear in the
> string. */
> const char *s = PyString_AS_STRING(str);
> const char *end = s + PyString_GET_SIZE(str);
> const char *q;
> for (q = s; q < end; q++) {
> char c = *q;
> if (c == '.' || c == 'e')
> isfloat = 1;
> else if (c == 'j')
> iscomplex = 1;
> else if (c != '-' && c != '+' && !isdigit(c) && !isspace(c)) {
> PyErr_Format(PyExc_ValueError, "invalid numeric value '%s'", s);
> return NULL;
> }
> }
>
> /* Now that the type is known, construct the number, leaving the
> actual error checking to the constructors. */
> if (iscomplex)
> return PyObject_CallFunctionObjArgs((PyObject *) &PyComplex_Type, str);
> else if (isfloat)
> return PyFloat_FromString(str, NULL);
> else
> /* handles ints and longs */
> return PyInt_FromString((char *) s, NULL, 10);
> }
>
> Would anyone else find this kind of function useful?
Yes.
Perhaps as PyNumber_FromString() ?!
--
Marc-Andre Lemburg
eGenix.com
Professional Python Services directly from the Source (#1, May 07 2008)
>>> Python/Zope Consulting and Support ... http://www.egenix.com/
>>> mxODBC.Zope.Database.Adapter ... http://zope.egenix.com/
>>> mxODBC, mxDateTime, mxTextTools ... http://python.egenix.com/
________________________________________________________________________
:::: Try mxODBC.Zope.DA for Windows,Linux,Solaris,MacOSX for free ! ::::
eGenix.com Software, Skills and Services GmbH Pastor-Loeh-Str.48
D-40764 Langenfeld, Germany. CEO Dipl.-Math. Marc-Andre Lemburg
Registered at Amtsgericht Duesseldorf: HRB 46611
More information about the capi-sig
mailing list