How to do python style string slicing in c++ [duplicate] - python

This question already has answers here:
C++ equivalent of Python String Slice?
(7 answers)
Closed 4 years ago.
Is it possible to implement a method through which I can do slicing in C++ using : operator.
For example,I define a C-style string as shown below:
char my_name[10] {"InAFlash"};
Can I implement a function or override any internal method to do the following:
cout << my_name[1:5] << endl;
Output: nAFl
Update 1: i tried with string type as below
#include <iostream>
#include <string>
using namespace std;
int main()
{
string my_name;
my_name = "Hello";
// strcpy(my_name[2,5],"PAD");
// my_name[2]='p';
cout << my_name[2:4];
return 0;
}
But, got the following error
helloWorld.cpp: In function 'int main()':
helloWorld.cpp:10:22: error: expected ']' before ':' token
cout << my_name[2:4];
^
helloWorld.cpp:10:22: error: expected ';' before ':' token

If you are stuck with C-style array, std::string_view (C++17) could be a good way to manipulate char[] without copying memory around:
#include <iostream>
#include <string_view>
int main()
{
char my_name[10] {"InAFlash"};
std::string_view peak(my_name+1, 4);
std::cout << peak << '\n'; // prints "nAFl"
}
Demo: http://coliru.stacked-crooked.com/a/fa3dbaf385fd53c5
With std::string, a copy would be necessary:
#include <iostream>
#include <string>
int main()
{
char my_name[10] {"InAFlash"};
std::string peak(my_name+1, 4);
std::cout << peak << '\n'; // prints "nAFl"
}
Demo: http://coliru.stacked-crooked.com/a/a16112ac3ffcd8de

If you want a copy of the string, then it can be done using iterators or substr:
std::string my_name("InAFlash");
std::string slice = my_name.substr(1, 4); // Note this is start index, count
If you want to slice it without creating a new string, then std::string_view (C++17) would be the way to go:
std::string view slice(&my_name[0], 4);

If you use std::string (the C++ way) you can
std::string b = a.substr(1, 4);

Related

Python dictionary to C++ map

I am very new to C++ and am trying to translate a dictionary into a C++ format. I can't quite seem to find the answer I am looking for from the previous questions submitted on here.
I have code as follows:
#include <iostream>
#include <map>
using namespace std;
typedef std::map<string, int> BasePairMap;
int main()
{
BasePairMap m;
m['power'] = 0;
m['select'] = 1;
m['backup'] = 2;
...
...
...
m['rewind'] = 71;
m['boxoffice'] = 240;
m['sky'] = 241;
return 0;
}
But I keep getting character overflow errors. How can I map string/int pairs together in C++?
Thanks
While many languages (such as Python) allow developers to use either single or double quotes for strings, in C++ you need to use double quotes (reference). Simple quotes are used for the char type which describes a single character (reference).
So your code should be:
#include <iostream>
#include <map>
using namespace std;
typedef std::map<string, int> BasePairMap;
int main()
{
BasePairMap m;
m["power"] = 0;
m["select"] = 1;
m["backup"] = 2;
// ...
m["rewind"] = 71;
m["boxoffice"] = 240;
m["sky"] = 241;
return 0;
}

How to insert a python code in C++?

i am trying to embed a code python in c++. I have this python code :
#include <Python.h>
int main(int arg)
{
Py_SetProgramName(argv[0]);
Py_Initialize();
PyRun_SimpleString("from time import time,ctime\n"
"print 'Today is',ctime(time())\0");
Py_Finalize();
return 0;
}
but what i want is something like that :
include
int main(int arg)
{
Py_SetProgramName(argv[0]);
int a = 5;
Py_Initialize();
PyRun_SimpleString("a = " + a);
Py_Finalize();
return 0;
}
but it does not work. I mean i want with python to display the value of the variable a.
Thank you :)
You could use std::to_string to convert your int to a string and then use std::string::c_str to get a temporary const char* to the internal data for the duration of the function call:
PyRun_SimpleString(("a = " + std::to_string(a)).c_str());
You have to use correct C syntax in the C code; in C, "a = "+a does not concatenate strings (as you might assume), but calculate a useless pointer that points a bytes behind the start of the constant string "a = ". With a being 5, there is nothing useful at that place.
Concatenating strings is not that straightforward in C; you need to handle preparing memory for the target, etc.; same for converting a number to a string. For example:
char buffer[30];
sprintf(buffer,"a = %d\n",a);
and then
PyRun_SimpleString(buffer);

How do I pass a pre-populated "unsigned char*" buffer to a C++ method using boost.python?

I have a C++ class with a member function that takes an unsigned char* buffer and an unsigned int length as arguments and operates on them. I've wrapped this class with Boost::Python and would like to pass a pre-populated buffer to the class from a Python script. The Python-side buffer is created with struct.pack. I can't figure out how to make the argument type match and keep getting Boost.Python.ArgumentError.
include/Example.h
#ifndef EXAMPLECLASS_H_
#define EXAMPLECLASS_H_
#include <cstdio>
class ExampleClass
{
public:
ExampleClass() {}
virtual ~ExampleClass() {}
void printBuffer(unsigned char* buffer, unsigned int length)
{
for (unsigned int i = 0; i < length; ++i)
{
printf("%c", buffer[i]);
}
printf("\n");
}
};
#endif
src/example.cpp
#include "Example.h"
int main(int argc, char** argv)
{
unsigned char buf[4];
buf[0] = 0x41;
buf[1] = 0x42;
buf[2] = 0x43;
buf[3] = 0x44;
ExampleClass e;
e.printBuffer(buf, 4);
return 0;
}
src/Example_py.cpp
#include <boost/python.hpp>
#include "Example.h"
using namespace boost::python;
BOOST_PYTHON_MODULE(example_py)
{
class_<ExampleClass>("ExampleClass")
.def("printBuffer", &ExampleClass::printBuffer)
;
}
scripts/example.py
#!/usr/bin/env python
import example_py
import struct
import ctypes
buf = struct.pack('BBBB', 0x41, 0x42, 0x43, 0x44)
print 'python:'
print buf
e = example_py.ExampleClass()
print 'c++:'
print e.printBuffer(ctypes.cast(ctypes.c_char_p(buf), ctypes.POINTER(ctypes.c_ubyte)), len(buf))
CMakeLists.txt (incomplete)
include_directories(
include
${Boost_INCLUDE_DIRS}
${PYTHON_INCLUDE_DIRS}
)
add_library(example_py
src/Example_py.cpp
)
target_link_libraries(example_py ${Boost_LIBRARIES} ${PYTHON_LIBRARIES})
set_target_properties(example_py PROPERTIES PREFIX "")
add_executable(example src/example.cpp)
target_link_libraries(example example_py)
Output
$ ./example
ABCD
$ ./scripts/example.py
python: ABCD
c++:
Traceback (most recent call last):
File "/home/dustingooding/example/scripts/example.py", line 13, in <module>
print 'c++:', e.printBuffer(ctypes.cast(ctypes.c_char_p(buf), ctypes.POINTER(ctypes.c_ubyte)), len(buf))
Boost.Python.ArgumentError: Python argument types in
ExampleClass.printBuffer(ExampleClass, LP_c_ubyte, int)
did not match C++ signature:
printBuffer(ExampleClass {lvalue}, unsigned char*, unsigned int)
I've tried a number of different approaches (passing 'buf' directly, passing 'buf' as a ctypes.c_char_p, creating a ctypes.ubyte array and populating it with the contents of 'buf' and passing it), but none seem to work.
I don't understand why 'LP_c_ubyte' and 'unsigned char*' don't match.
EDIT
Here's a Github project with a ready-to-go codebase. Feel free to use this. I've added #Tanner's fix. https://github.com/dustingooding/boost_python_ucharp_example
It may be worth considering exposing a Pythonic auxiliary function as the ExampleClass.printBuffer method to Python, that delegates to the c-ish ExampleClass::printBuffer member function. For instance, this would allow the Python users to invoke:
import example
import struct
buf = struct.pack('BBBB', 0x41, 0x42, 0x43, 0x44)
e.printBuffer(buf)
Rather than requiring the user to perform the correct ctypes cast and sizing.
The struct.pack() method returns a str object in Python2 and a bytes object in Python3, so the auxiliary C++ function would need to populate a continuous block of memory with the elements of from either str or bytes. The boost::python::stl_input_iterator can provide a convenient way to construct C++ containers, such as std::vector<char>, from a Python object, such as str or bytes. The only oddity is that stl_input_iterator expects the Python type to support the iterable protocol, which str does not do. However, the builtin iter() Python method can be used to create an iterable object.
/// #brief Auxiliary function used to allow a Python iterable object with char
/// elements to be passed to ExampleClass.printBuffer().
void example_class_print_buffer_wrap(
ExampleClass& self,
boost::python::object py_buffer)
{
namespace python = boost::python;
// `str` objects do not implement the iterator protcol (__iter__),
// but do implement the sequence protocol (__getitem__). Use the
// `iter()` builtin to create an iterator for the buffer.
// >>> __builtins__.iter(py_buffer)
python::object locals(python::borrowed(PyEval_GetLocals()));
python::object py_iter = locals["__builtins__"].attr("iter");
python::stl_input_iterator<char> begin(
py_iter(py_buffer)), end;
// Copy the py_buffer into a local buffer with known continguous memory.
std::vector<char> buffer(begin, end);
// Cast and delegate to the printBuffer member function.
self.printBuffer(
reinterpret_cast<unsigned char*>(&buffer[0]),
buffer.size());
}
With the auxiliary function created, one just needs to expose it as the ExampleClass.printBuffer method:
BOOST_PYTHON_MODULE(example)
{
namespace python = boost::python;
python::class_<ExampleClass>("ExampleClass")
.def("printBuffer", &example_class_print_buffer_wrap)
;
}
Here is a complete example demonstrating this approach:
#include <cstdio>
#include <vector>
#include <boost/python.hpp>
#include <boost/python/stl_iterator.hpp>
// Mocks...
/// #brief Legacy class that cannot be changed.
class ExampleClass
{
public:
void printBuffer(unsigned char* buffer, unsigned int length)
{
for (unsigned int i = 0; i < length; ++i)
{
printf("%c", buffer[i]);
}
printf("\n");
}
};
/// #brief Auxiliary function used to allow a Python iterable object with char
/// elements to be passed to ExampleClass.printBuffer().
void example_class_print_buffer_wrap(
ExampleClass& self,
boost::python::object py_buffer)
{
namespace python = boost::python;
// `str` objects do not implement the iterator protcol (__iter__),
// but do implement the sequence protocol (__getitem__). Use the
// `iter()` builtin to create an iterator for the buffer.
// >>> __builtins__.iter(py_buffer)
python::object locals(python::borrowed(PyEval_GetLocals()));
python::object py_iter = locals["__builtins__"].attr("iter");
python::stl_input_iterator<char> begin(
py_iter(py_buffer)), end;
// Copy the py_buffer into a local buffer with known continguous memory.
std::vector<char> buffer(begin, end);
// Cast and delegate to the printBuffer member function.
self.printBuffer(
reinterpret_cast<unsigned char*>(&buffer[0]),
buffer.size());
}
BOOST_PYTHON_MODULE(example)
{
namespace python = boost::python;
python::class_<ExampleClass>("ExampleClass")
.def("printBuffer", &example_class_print_buffer_wrap)
;
}
Interactive usage:
>>> import example
>>> import struct
>>> buf = struct.pack('BBBB', 0x41, 0x42, 0x43, 0x44)
>>> print 'python:', buf
python: ABCD
>>> e = example.ExampleClass()
>>> e.printBuffer(buf)
ABCD
The python documentation lists the following in the chapter Fundamental Data Types:
class ctypes.c_char_p
Represents the C char * datatype when it points to a zero-terminated string. For a general character pointer
that may also point to binary data, POINTER(c_char) must be used. The
constructor accepts an integer address, or a string.
shows that you should probably use a c_char_p type. If you use the POINTER() functions this will be a LP_c_char_p.
The type
LP_c_ubyte /* corresponds to */ unsigned char;
you should probably use
LP_c_char_p /* which corresponds to */ char *;
Update:
I've corrected the types above. Also: I'm not a python expert, so I might have it wrong. There is also this answer.

Return vector<string> by reference

I have a SWIG class that receives an vector of strings -vector<string> (CSCHSwig), this class uses a. LIB another project that returns another vector of strings by reference.
CSCHSwig.cpp
#include CSCHSwig.h
vector < string> CSCHSwig::CSwig(vector < string> a_InputArgs){
vector < string> a_OutputArgs;
int resposta = ClassLib->SendRequest(a_InputArgs, a_OutputArgs);
return a_OutputArgs
}
CSCHSwig.h
#include < string>
#include < vector>
using namespace std;
class CSCHSwig { public:
CSCHSwig();
virtual ~CSCHSwig();
vector <string> CSwig(const vector < string> a_InputArgs);
}
CSCHSwig.i
/* File : CSCHSwig.i */
%module CSCHSwig
%{
#include "..\..\..\Incl\CSCHSwig.h"
%}
%include <std_string.i>
%include <std_vector.i>
%include "typemaps.i"
namespace std {
%template(a_OutpuArgs) vector < string>;
}
%include "..\..\..\Incl\CSCHSwig.h"
An example of ClassLib:
ClassLib.cpp
int ClassLib::SendRequest(const vector < string>& a_InputArgs, vector < string>& a_OutputArgs, {
vector < string> Vector;
Vector.push_back("pReturnStatus");
Vector.push_back("1");
a_OutputArgs = Vector;
return 1;
}
ClassLib.h
class ClassLib
{
public:
int SendRequest(const vector < string>& a_InputArgs, vector < string>& a_OutputArgs);
}
I've tested the SWIG class and it is working perfectly, I call CSwig method from python passing a list of strings. The problem is when the CSwig method calls the method SendRequest ClassLib.
int resposta = ClassLib->SendRequest(a_InputArgs, a_OutputArgs);
Execution is terminated, returns no error. The tests I made the "mistake" happens when the a_OutputArgs argument is handled within the method and returns an array of strings. Maybe I need to put something in the .i file for this to work.
I found the problem. I use MS Visual Studio 2008 and the setting was different projects. In Project Properties> General> Use of MFC set:
Use MFC in a Shared DLL

Python/SWIG: Output an array

I am trying to output an array of values from a C function wrapped using SWIG for Python. The way I am trying to do is using the following typemap.
Pseudo code:
int oldmain() {
float *output = {0,1};
return output;
}
Typemap:
%typemap(out) float* {
int i;
$result = PyList_New($1_dim0);
for (i = 0; i < $1_dim0; i++) {
PyObject *o = PyFloat_FromDouble((double) $1[i]);
PyList_SetItem($result,i,o);
}
}
My code compiles well, but it hangs when I run access this function (with no more ways to debug it).
Any suggestions on where I am going wrong?
Thanks.
The easiest way to allow the length to vary is to add another output parameter that tells you the size of the array too:
%module test
%include <stdint.i>
%typemap(in,numinputs=0,noblock=1) size_t *len {
size_t templen;
$1 = &templen;
}
%typemap(out) float* oldmain {
int i;
$result = PyList_New(templen);
for (i = 0; i < templen; i++) {
PyObject *o = PyFloat_FromDouble((double)$1[i]);
PyList_SetItem($result,i,o);
}
}
%inline %{
float *oldmain(size_t *len) {
static float output[] = {0.f, 1.f, 2, 3, 4};
*len = sizeof output/sizeof *output;
return output;
}
%}
This is modified from this answer to add size_t *len which can be used to return the length of the array at run time. The typemap completely hides that output from the Python wrapper though and instead uses it in the %typemap(out) instead of a fixed size to control the length of the returned list.
This should get you going:
/* example.c */
float * oldmain() {
static float output[] = {0.,1.};
return output;
}
You are returning a pointer here, and swig has no idea about the size of it. Plain $1_dim0 would not work, so you would have to hard code or do some other magic. Something like this:
/* example.i */
%module example
%{
/* Put header files here or function declarations like below */
extern float * oldmain();
%}
%typemap(out) float* oldmain {
int i;
//$1, $1_dim0, $1_dim1
$result = PyList_New(2);
for (i = 0; i < 2; i++) {
PyObject *o = PyFloat_FromDouble((double) $1[i]);
PyList_SetItem($result,i,o);
}
}
%include "example.c"
Then in python you should get:
>> import example
>> example.oldmain()
[0.0, 1.0]
When adding typemaps you may find -debug-tmsearch very handy, i.e.
swig -python -debug-tmsearch example.i
Should clearly indicate that your typemap is used when looking for a suitable 'out' typemap for float *oldmain. Also if you just like to access c global variable array you can do the same trick using typemap for varout instead of just out.

Categories

Resources