问题
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?
回答1:
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).
回答2:
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
- Calling C functions in Python
- Issue returning values from C function called from Python
回答3:
parse the number yourself.
a recursive-descent parser is very easy for this kind of input. first write a grammar:
float ::= ipart ('.' fpart)* ('e' exp)*
ipart ::= digit+
fpart ::= digit+
exp ::= ('+'|'-') digit+
digit = ['0'|'1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9']
now converting this grammar to a function should be straightforward...
回答4:
I'd use a regular expression for this:
import re
mystring = "1.3 times 456.789 equals 593.8257 (or 5.93E2)"
def findfloats(s):
regex = re.compile(r"[+-]?\b\d+(?:\.\d+)?(?:e[+-]?\d+)?\b", re.I)
for match in regex.finditer(mystring):
yield (match.group(), match.start(), match.end())
This finds all floating point numbers in the string and returns them together with their positions.
>>> for item in findfloats(mystring):
... print(item)
...
('1.3', 0, 3)
('456.789', 10, 17)
('593.8257', 25, 33)
('5.93E2', 38, 44)
来源:https://stackoverflow.com/questions/7564899/python-equivalent-to-c-strtod