我正在努力将C ++程序的一部分转换为Python,但是我在替换C函数strtod时遇到了一些麻烦。 我正在处理的字符串由简单的数学方程组成,例如“KM / 1000.0”。问题是两个常量和数字是混合的,因此我无法使用float()。
如何编写Python函数来模拟strtod
,它返回转换后的数字和下一个字符的位置?
答案 0 :(得分:3)
我不知道会有任何现有的功能。
但是,使用正则表达式编写一个很容易:
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)
更好的整体方法可能是构建一个lexical scanner,首先对表达式进行标记,然后使用一系列标记而不是直接使用字符串(或者实际上是整个生猪并构建一个yacc-风格解析器)。
答案 1 :(得分:2)
您可以创建一个简单的C strtod
包装器:
#include <stdlib.h>
double strtod_wrap(const char *nptr, char **endptr)
{
return strtod(nptr, endptr);
}
编译:
gcc -fPIC -shared -o libstrtod.dll strtod.c
(如果您使用的是Python 64位,编译器也必须是64位)
并使用ctypes
从lib中使用.dll
调用它(在linux目录中将.so
更改为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"))
,在下面的代码中,这已经在Windows上进行了测试):
(12.5, b'hello')
打印:
ctypes
(这并不像看起来那么难,因为我在10分钟前学会了如何做到这一点)
有用的Q&amp;关于const myStrings = {
a: `myStringA${test}`,
b: `myStringB${test}`
}
答案 2 :(得分:0)
我会使用正则表达式:
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())
这将查找字符串中的所有浮点数,并将它们与位置一起返回。
>>> for item in findfloats(mystring):
... print(item)
...
('1.3', 0, 3)
('456.789', 10, 17)
('593.8257', 25, 33)
('5.93E2', 38, 44)
答案 3 :(得分:0)
自己解析数字。
递归下降解析器对于这种输入非常容易。 先写一个语法:
float ::= ipart ('.' fpart)* ('e' exp)*
ipart ::= digit+
fpart ::= digit+
exp ::= ('+'|'-') digit+
digit = ['0'|'1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9']
现在将此语法转换为函数应该很简单......