I am working on converting parts of a C++ program to Python, but I have some trouble replacing the C function strtod. The strings I'm working on consists of simple mathmatical-ish equations, such as "KM/1000.0". The problem is that the both constants and numbers are mixed and I'm therefore unable to use float().
How can a Python function be written to simulate strtod
which returns both the converted number and the position of the next character?
I'm not aware of any existing functions that would do that.
However, it's pretty easy to write one using regular expressions:
import re
# returns (float,endpos)
def strtod(s, pos):
m = re.match(r'[+-]?\d*[.]?\d*(?:[eE][+-]?\d+)?', s[pos:])
if m.group(0) == '': raise ValueError('bad float: %s' % s[pos:])
return float(m.group(0)), pos + m.end()
print strtod('(a+2.0)/1e-1', 3)
print strtod('(a+2.0)/1e-1', 8)
A better overall approach might be to build a lexical scanner that would tokenize the expression first, and then work with a sequence of tokens rather than directly with the string (or indeed go the whole hog and build a yacc-style parser).
You can create a simple C strtod
wrapper:
#include <stdlib.h>
double strtod_wrap(const char *nptr, char **endptr)
{
return strtod(nptr, endptr);
}
compile with:
gcc -fPIC -shared -o libstrtod.dll strtod.c
(if you're using Python 64 bit, the compiler must be 64-bit as well)
and call it using ctypes
from python (linux: change .dll
to .so
in the lib target and in the code below, this was tested on Windows):
import ctypes
_strtod = ctypes.CDLL('libstrtod.dll')
_strtod.strtod_wrap.argtypes = (ctypes.c_char_p, ctypes.POINTER(ctypes.c_char_p))
_strtod.strtod_wrap.restype = ctypes.c_double
def strtod(s):
p = ctypes.c_char_p(0)
s = ctypes.create_string_buffer(s.encode('utf-8'))
result = _strtod.strtod_wrap(s, ctypes.byref(p))
return result,ctypes.string_at(p)
print(strtod("12.5hello"))
prints:
(12.5, b'hello')
(It's not as hard as it seems, since I learned how to do that just 10 minutes ago)
Useful Q&As about ctypes
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With