7

我正在将 C++ 程序的一部分转换为 Python,但是在替换 C 函数strtod时遇到了一些麻烦。我正在处理的字符串由简单的数学方程式组成,例如“KM/1000.0”。问题是常量和数字都是混合的,因此我无法使用 float()。

如何编写 Python 函数来模拟strtod返回转换后的数字和下一个字符的位置?

4

4 回答 4

4

我不知道有任何现有的功能可以做到这一点。

但是,使用正则表达式很容易编写:

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)

更好的整体方法可能是构建一个词法扫描器,它首先对表达式进行标记,然后使用一系列标记而不是直接使用字符串(或者确实全力以赴并构建一个 yacc 样式的解析器)。

于 2011-09-27T06:22:21.303 回答
2

您可以创建一个简单的 Cstrtod包装器:

#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 位)

并使用从 python 调用它ctypes(linux:在 lib 目标和下面的代码中更改.dll.so,这是在 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"))

印刷:

(12.5, b'hello')

(这并不像看起来那么难,因为我在 10 分钟前就学会了如何做到这一点)

有用的问答ctypes

于 2018-05-21T19:57:57.547 回答
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)
于 2011-09-27T06:23:21.093 回答
0

自己解析数字。

对于这种输入,递归下降解析器非常容易。先写一个语法:

float ::= ipart ('.' fpart)* ('e' exp)*
ipart ::= digit+
fpart ::= digit+
exp   ::= ('+'|'-') digit+
digit = ['0'|'1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9']

现在将此语法转换为函数应该很简单......

于 2011-09-27T06:27:40.700 回答