[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