我正在用Cython实现一个功能,该功能要求在某个时候从C ++ char
中删除一些std::string
。为此,我将使用std::string::erase()
。但是,当我尝试使用它时,Cython强制将对象设为bytes()
而不是std::string()
,这时它找不到.erase()
。
为说明问题,这是一个最小的示例(使用IPython + Cython魔术):
%load_ext Cython
%%cython --cplus -c-O3 -c-march=native -a
from libcpp.string cimport string
cdef string my_func(string s):
cdef char c = b'\0'
cdef size_t s_size = s.length()
cdef size_t i = 0
while i + 1 <= s_size:
if s[i] == c:
s.erase(i, 1)
i += 1
return s
def cy_func(string b):
return my_func(b)
这可以编译,但是它指示.remove()
行上的Python交互,例如当我尝试使用它时,例如
b = b'ciao\0pippo\0'
print(b)
cy_func(b)
我得到:
AttributeError跟踪(最近一次通话) AttributeError:“ bytes”对象没有属性“ erase”
忽略异常:“ _ cython_magic_5beaeb4004c3afc6d85b9b158c654cb6.my_func” AttributeError:“ bytes”对象没有属性“ erase”
我该如何解决?
s.erase(i, 1)
替换为s[i] == 10
,则我得到my_func()
且没有Python交互(甚至可以使用nogil
指令)。.replace(b'\0', b'')
在Python中实现此功能,但这是我希望使用Cython优化的更长算法的一部分。答案 0 :(得分:1)
您可以在数组边界之后访问。修复它,您的代码将正常工作。
在erase
之后,字符串的长度减小。同样,条件i < s_size
看起来比i + 1 <= s_size
好。最后,i
不得在erase
之后增加,新的字符将进入该索引。
while i < s_size:
if s[i] == c:
s.erase(i, 1)
s_size -= 1
else:
i += 1
下面的 b
是字节数组。尝试调用.decode
将其转换为字符串。
b = b'ciao\0pippo\0'
print(b)
cy_func(b.decode('ASCII'))
答案 1 :(得分:1)
我不知道Cython为什么产生它正在产生的代码-string.pxd中甚至没有erase
,所以Cython应该产生错误。
最简单的解决方法是引入包装erase
的函数std::string::erase
:
cdef extern from *:
"""
#include <string>
std::string &erase(std::string& s, size_t pos, size_t len){
return s.erase(pos, len);
}
"""
string& erase(string& s, size_t pos, size_t len)
# replace s.erase(i,1) -> erase(s,i,1)
但是,这不是用C ++擦除零的方式:它有故障(请参见@MS answer进行修复)并且具有O(n^2)
运行时间(只需在{{ 1}}),正确的方法是使用remove/erase-idiom:
b"\x00"*10**6
很难被滥用的%%cython --cplus
from libcpp.string cimport string
cdef extern from *:
"""
#include <string>
#include <algorithm>
void remove_nulls(std::string& s){
s.erase(std::remove(s.begin(), s.end(), 0), s.end());
}
"""
void remove_nulls(string& s)
cdef string my_func(string s):
remove_nulls(s)
return s
。
再说一遍,涉及到每个值传递`std :: string'。签名:
O(n)
意味着,有两个(不必要的)副本(不可能使用RVO),最好避免并通过引用传递cdef string my_func(string s)
...
return s
(至少在s
函数中):
cdef