Copy a substring from const char* to std::string - c++

Would there be any copy function available that allows a substring to std::string?
Example -
const char *c = "This is a test string message";
I want to copy substring "test" to std::string.

You can use a std::string iterator constructor to initialize it with a substring of a C string e.g.:
const char *sourceString = "Hello world!";
std::string testString(sourceString + 1, sourceString + 4);

Well, you can write one:
#include <assert.h>
#include <string.h>
#include <string>
std::string SubstringOfCString(const char *cstr,
size_t start, size_t length)
{
assert(start + length <= strlen(cstr));
return std::string(cstr + start, length);
}

You can use this std::string's constructor:
string(const string& str, size_t pos, size_t n = npos);
Usage:
std::cout << std::string("012345", 2, 4) << std::endl;
const char* c = "This is a test string message";
std::cout << std::string(c, 10, 4) << std::endl;
Output:
2345
test
(Edit: showcase example)

You might want to use a std::string_view (C++17 onwards) as an alternative to std::string:
#include <iostream>
#include <string_view>
int main()
{
static const auto s{"This is a test string message"};
std::string_view v{s + 10, 4};
std::cout << v <<std::endl;
}

const char *c = "This is a test string message";
std::string str(c);
str.substr(0, 4);
const char *my_c = str.c_str(); // my_c == "This"

Related

How to imitate std::string's find_first_not_of using strspn

I'm trying to create a custom string class similar to std::string.
And I'm having a trouble implementing 'find_first_not_of'.
Here's my test code
#include <iostream>
class String {
private:
char *m_data;
int m_length;
char *alloc(int size);
int length() const {return m_length;}
int size() const {return m_length;}
const char *c_str() const {return m_data;}
public:
String(const char *str=0);
int find_first_not_of(const char *str);
static const int npos;
};
const int String::npos = -1;
char * String::alloc(int size)
{
char * str = new char[size+1];
return str;
}
String::String(const char *str)
{
if (!str) str = "";
m_length = static_cast<int>(strlen(str));
m_data = alloc(m_length);
strcpy(m_data, str);
}
int String::find_first_not_of(const char *str)
{
size_t len = strspn(c_str(), str);
if (len == 0)
return -1;
else
return len;
}
int main(int argc, const char * argv[]) {
String A = "123";
std::string B = "123";
if (A.find_first_not_of("0123456789") == -1)
std::cout << "A is digit" << std::endl;
else
std::cout << "A is not digit" << std::endl;
if (B.find_first_not_of("0123456789") == -1)
std::cout << "B is digit" << std::endl;
else
std::cout << "B is not digit" << std::endl;
return 0;
}
And this is the result I see if I run the code.
A is not digit
B is digit
Program ended with exit code: 0
Can someone please point me what I'm missing?
Thanks!
You are confusing your String::find_first_not_of with std::string::find_first_not_of. They are different functions that have different functionality.
I really don't understand what String::find_first_not_of needs to do, but here is what each of them returns (one the length of the string and the other one the position):
std::string::find_first_if_not (from here):
The position of the first character that does not match.
If no such characters are found, the function returns string::npos.
strspn (from here):
The length of the initial portion of str1 containing only characters that appear in str2.
Therefore, if all of the characters in str1 are in str2, the function returns the length of the entire str1 string, and if the first character in str1 is not in str2, the function returns zero.
So even the inner working of the functions are different.
You should be able to follow based on this info.
This one worked just like std::string's find_first_not_of.
int String::find_first_not_of(const char *str, int pos)
{
const int len = static_cast<int>(strspn(c_str() + pos, str));
if (len + pos == m_length)
return -1; //npos
else
return len + pos;
}
#Garmekain's explanation was really helpful. Thank you.

string Multiplication in C++

There is already a question for this here: How to repeat a string a variable number of times in C++? However because the question was poorly formulated primarily answers about character multiplication were given. There are two correct, but expensive answers, so I'll be sharpening the requirement here.
Perl provides the x operator: http://perldoc.perl.org/perlop.html#Multiplicative-Operators which would let me do this:
$foo = "0, " x $bar;
I understand that I can do this with the helper functions such as those in the other answer. I want to know can I do this without my own helper function? My preference would be something that I could initialize a const string with, but if I can't do that I'm pretty sure that this could be answered with a standard algorithm and a lambda.
You can either override the multiplication operator
#include <string>
#include <sstream>
#include <iostream>
std::string operator*(const std::string& str, size_t times)
{
std::stringstream stream;
for (size_t i = 0; i < times; i++) stream << str;
return stream.str();
}
int main() {
std::string s = "Hello World!";
size_t times = 5;
std::string repeated = s * times;
std::cout << repeated << std::endl;
return 0;
}
... or use a lambda ...
#include <string>
#include <sstream>
#include <iostream>
int main() {
std::string s = "Hello World!";
size_t times = 5;
std::string repeated = [](const std::string& str, size_t times) {std::stringstream stream; for (size_t i = 0; i < times; i++) stream << str; return stream.str(); } (s, times);
std::cout << repeated << std::endl;
return 0;
}
... or use a lambda with reference capturing ...
#include <string>
#include <sstream>
#include <iostream>
int main() {
std::string s = "Hello World!";
size_t times = 5;
std::string repeated = [&s, &times]() {std::stringstream stream; for (size_t i = 0; i < times; i++) stream << str; return stream.str(); }();
std::cout << repeated << std::endl;
return 0;
}
Instead of using std::stringstream you could also use std::string in combination with std::string::reserve(size_t) as you already know (or can calculate) the size of the result string.
std::string repeated; repeated.reserve(str.size() * times);
for (size_t i = 0; i < times; i++) repeated.append(str);
return repeated;
This might be faster: Compare http://goo.gl/92hH9M with http://goo.gl/zkgK4T
It is possible to do this using just a standard algorithm and a lambda with generate_n, but it still cannot initialize a const string it needs to be done in a separate line:
string foo;
const auto bar = 13U;
generate_n(back_inserter(foo), bar * 3U, [](){
static const char multiplicand[] = "0, ";
static const auto length = strlen(multiplicand);
static auto i = 0U;
return multiplicand[i++ % length];});
I've created a live example here: http://ideone.com/uIt2Ee But as is probably been made plain by all the question comments, the requirement of doing this in a single line results in inferior code. Right off the bat, we can see that the bare constant, 3, represents the size of multiplicand and unnecessarily requires changes to the initialization of multiplicand to also update this literal.
The obvious improvement that should be made is:
string foo;
const auto bar = 13U;
const char multiplicand[] = "0, ";
const auto length = strlen(multiplicand);
generate_n(back_inserter(foo), bar * length, [&](){
static auto i = 0U;
return multiplicand[i++ % length];
});
The next improvement would be eliminating the reallocation as foo grows, which could be expensive if bar or length is large. That can be accomplished by constructing foo with sufficient space to contain the entire generated string:
const auto bar = 13U;
const char multiplicand[] = "0, ";
const auto length = strlen(multiplicand);
string foo(bar * length, '\0');
generate_n(foo.begin(), bar * length, [&](){
static auto i = 0U;
return multiplicand[i++ % length];
});
[Live Example]

C++ regex - replacing substring in char

I have written the following function to replace substrings in a char. This way involves converting to a std::string then converting back to a const char. Is this the most efficient way or could I do it without this conversion or even a better way?!
const char* replaceInString(const char* find, const char* str, const char* replace)
{
std::string const text(str);
std::regex const reg(find);
std::string const newStr = std::regex_replace(text, reg, replace);
//Convert back to char
char *newChar = new char[newStr.size() + 1];
std::copy(newStr.begin(), newStr.end(), newChar);
newChar[newStr.size()] = '\0'; // terminating 0
return newChar;
}
const char* find = "hello";
const char* replace = "goodbye";
const char* oldStr = "hello james";
const char* newStr = m->replaceInString(find, oldStr, replace);
Assuming that you want a function to be called from a .c file you could use strdup (see code below).
#include <string>
#include <regex>
#include <cstdio>
#include <cstdlib>
char* replaceInString(char const *find, char const *str, char const *replace)
{
return strdup(std::regex_replace(std::string(str), std::regex(find), replace).c_str());
}
int main()
{
char *newStr = replaceInString("hello", "hello james", "goodbye");
printf("newStr = %s\n", newStr);
free(newStr);
return 0;
}
Note however that you have to free the returned memory after you're done.
Otherwise, as #jerry-coffin suggested go all the way with std::string (see code below):
#include <string>
#include <regex>
#include <iostream>
std::string replaceInString(std::string const &find, std::string const &str, std::string const &replace)
{
return std::regex_replace(std::string(str), std::regex(find), replace);
}
int main()
{
std::string str = replaceInString(std::string("hello"), std::string("hello james"), std::string("goodbye"));
std::cout << str << std::endl;
return 0;
}

How do I write functions that accept unlimited arguments?

I have only been able to find one way for functions to take a variable amount of arguments.
It's this way:
#include <iostream>
#include <stdarg.h>
using namespace std;
void Print(int argumentAmount, ... );
int main()
{
Print(5,11,22,33,44,55);
}
void Print(int argumentAmount, ... ){
va_list arguments;
va_start(arguments, argumentAmount);
int parameter;
for(int i = 0; i < argumentAmount; ++i ){
parameter = va_arg(arguments, int);
cout << parameter << endl;
}
va_end(arguments);
return;
}
2 Problems:
1.) I have to specify how many arguments I'm sending in- not desirable
2.) I can't figure out how to modify it so it will output strings.
Would something like this be possible without having to overload the function multiple times:
void Output(/*not sure how this would look*/);
int main(){
Output("hello","world");
Output("this","is","a","test");
Output("As","many","strings","as","you","want","may","be","passed","in");
return 0;
}
void Output(/*not sure how this would look*/){
//loop through each string passed in and output it
}
What about this:
void Capitalize(/*all passed by reference*/);
int main(){
string s1 = "hello";
string s2 = "world";
string s3 = "this";
string s4 = "is";
string s5 = "a";
string s6 = "test";
string s7 = "as";
string s8 = "many";
string s9 = "strings";
string s10 = "as";
string s11 = "you";
string s12 = "want";
Capitalize(s1,s2);
Capitalize(s3,s4,s5,s6);
Capitalize(s7,s8,s9,s10,s11,s12);
return 0;
}
void Capitalize(/*all passed by reference*/){
//capitalize each string passed in
}
All I can think to do is:
-overload the function multiple times
-have the function accept some type of container instead
If this is NOT POSSIBLE, could someone explain why the compiler is not capable of accomplishing a task like this.
With variadic templates in C++11, you can do something like this (see the result at ideone)
#include <string>
#include <iostream>
void Output() {
std::cout<<std::endl;
}
template<typename First, typename ... Strings>
void Output(First arg, const Strings&... rest) {
std::cout<<arg<<" ";
Output(rest...);
}
int main() {
Output("I","am","a","sentence");
Output("Let's","try",1,"or",2,"digits");
return 0;
}
Quick and simple answer.
For C++ you need to specify either the number of arguments or a sentinel value to indicate the end of arguments.
Your first example is a good example of specing the count, you could also do:
void Print(const char *arg, ... ){
va_list arguments;
for (va_start(arguments, arg); arg != NULL; arg = va_arg(arguments, const char *)) {
cout << arg << endl;
}
va_end(arguments);
}
Where your calling convention is:
Print("foo","bar",NULL);
If you want to take it to the next level, you can mix in a bit of the C Preprocessor and do:
#define mPrint(...) Print(__VA_ARGS__, NULL)
Now you can just say:
mPrint("fooo","bar");
And the macro will NULL terminate the call.
Instead of passing in the count, you can have a special "trailing" argument (either nullptr or a pointer to some hard-coded "magic" string) and your variable-argument functions should stop extracting more arguments once they see the trailing one. That can ease your coding a bit.
You could also pass pointers (references) to containers, containing (or pointing at/referencing) your strings. Anything that can somehow link all your individual arguments will do (e.g. a vector).
Example (might be not very idiomatic, but should serve as an illustration):
#include <iostream>
#include <string>
#include <cstdarg>
#include <cctype>
#include <vector>
using namespace std;
void AntiCapitalize(vector<string*>& v);
void Capitalize(string* s, ...);
void Print(string* s, ...);
int main()
{
string s1 = "hello";
string s2 = "world";
string s3 = "this";
string s4 = "is";
string s5 = "a";
string s6 = "test";
string s7 = "as";
string s8 = "many";
string s9 = "strings";
string s10 = "as";
string s11 = "you";
string s12 = "want";
Capitalize(&s1, &s2, 0);
Capitalize(&s3, &s4, &s5, &s6, 0);
Capitalize(&s7, &s8, &s9, &s10, &s11, &s12, 0);
Print(&s1, &s2, 0);
Print(&s3, &s4, &s5, &s6, 0);
Print(&s7, &s8, &s9, &s10, &s11, &s12, 0);
vector<string*> v;
v.push_back(&s1);
v.push_back(&s2);
v.push_back(&s3);
v.push_back(&s4);
v.push_back(&s5);
v.push_back(&s6);
v.push_back(&s7);
v.push_back(&s8);
v.push_back(&s9);
v.push_back(&s10);
v.push_back(&s11);
v.push_back(&s12);
AntiCapitalize(v);
Print(&s1, &s2, 0);
Print(&s3, &s4, &s5, &s6, 0);
Print(&s7, &s8, &s9, &s10, &s11, &s12, 0);
return 0;
}
void Capitalize(string* s, ...)
{
va_list ap;
va_start(ap, s);
while (s)
{
string::size_type i = 0;
while ((*s)[i] != '\0')
{
(*s)[i] = toupper((*s)[i]);
i++;
}
s = va_arg(ap, string*);
}
va_end(ap);
}
void Print(string* s, ...)
{
va_list ap;
va_start(ap, s);
while (s)
{
cout << *s << endl;
s = va_arg(ap, string*);
}
va_end(ap);
}
void AntiCapitalize(vector<string*>& v)
{
vector<string*>::iterator it;
for (it = v.begin(); it != v.end(); it++)
{
string::size_type i = 0;
while ((**it)[i] != '\0')
{
(**it)[i] = tolower((**it)[i]);
i++;
}
}
}
Output:
HELLO
WORLD
THIS
IS
A
TEST
AS
MANY
STRINGS
AS
YOU
WANT
hello
world
this
is
a
test
as
many
strings
as
you
want
I think there is another possible solution:
You could overload an operator '<<' like this:
class OutputObject {
public:
// Some class functions/members
};
template<class T>
static operator << (OutputObject& out, T temp) {
cout << temp;
}
static OutputObject Obj = OutputObject();
And then you can do the following in the main:
#include "OutputObject.hpp"
#include <string>
using namespace std;
int main(void) {
string str = "Hello World";
Obj << 12 << str << 3.14f << "C++";
Obj << 12;
Obj << str;
return(0);
};
If I did something wrong or there is a reason not to that please
tell me, that was just my Idea of infinite parameters.
I was not able to test it yet, but I think it should work.

iconv only works once

I try to make method which converts s-jis string to utf-8 string using iconv.
I wrote a code below,
#include <iconv.h>
#include <iostream>
#include <stdio.h>
using namespace std;
#define BUF_SIZE 1024
size_t z = (size_t) BUF_SIZE-1;
bool sjis2utf8( char* text_sjis, char* text_utf8 )
{
iconv_t ic;
ic = iconv_open("UTF8", "SJIS"); // sjis->utf8
iconv(ic , &text_sjis, &z, &text_utf8, &z);
iconv_close(ic);
return true;
}
int main(void)
{
char hello[BUF_SIZE] = "hello";
char bye[BUF_SIZE] = "bye";
char tmp[BUF_SIZE] = "something else";
sjis2utf8(hello, tmp);
cout << tmp << endl;
sjis2utf8(bye, tmp);
cout << tmp << endl;
}
and, output should be
hello
bye
but in fact,
hello
hello
Does anyone know why this phenomenon occurs? What's wrong with my program?
Note that "hello" and "bye" are Japanese s-jis strings in my original program, but I altered it to make program easy to see.
I think you are misusing the iconv function by passing it the global variable z. The first time you call sjis2utf8, z is decremented to 0. The second call to sjis2utf8 have no effect (z==0) and leaves tmp unchanged.
From the iconv documentation :
size_t iconv (iconv_t cd,
const char* * inbuf, size_t * inbytesleft,
char* * outbuf, size_t * outbytesleft);
The iconv function converts one multibyte character at a time, and for each character conversion it increments *inbuf and decrements *inbytesleft by the number of converted input bytes, it increments *outbuf and decrements *outbytesleft by the number of converted output bytes, and it updates the conversion state contained in cd.
You should use two separate variables for the buffers lengths :
size_t il = BUF_SIZE - 1 ;
size_t ol = BUF_SIZE - 1 ;
iconv(ic, &text_sjis, &il, &text_utf8, &ol) ;
Then check the return value of iconv and the buffers lengths for the conversion success.
#include <iconv.h>
#include <iostream>
#include <stdio.h>
#include <string.h>
using namespace std;
const size_t BUF_SIZE=1024;
class IConv {
iconv_t ic_;
public:
IConv(const char* to, const char* from)
: ic_(iconv_open(to,from)) { }
~IConv() { iconv_close(ic_); }
bool convert(char* input, char* output, size_t& out_size) {
size_t inbufsize = strlen(input)+1;// s-jis string should be null terminated,
// if s-jis is not null terminated or it has
// multiple byte chars with null in them this
// will not work, or to provide in other way
// input buffer length....
return iconv(ic_, &input, &inbufsize, &output, &out_size);
}
};
int main(void)
{
char hello[BUF_SIZE] = "hello";
char bye[BUF_SIZE] = "bye";
char tmp[BUF_SIZE] = "something else";
IConv ic("UTF8","SJIS");
size_t outsize = BUF_SIZE;//you will need it
ic.convert(hello, tmp, outsize);
cout << tmp << endl;
outsize = BUF_SIZE;
ic.convert(bye, tmp, outsize);
cout << tmp << endl;
}
based on Kleist's answer
You must put length of entry string in third parameter of iconv.
Try:
//...
int len = strlen(text_sjis);
iconv(ic , &text_sjis, &len, &text_utf8, &z);
//...
size_t iconv (iconv_t cd,
const char* * inbuf, size_t * inbytesleft,
char* * outbuf, size_t * outbytesleft);
iconv changes the value pointed to by inbytesleft. So after your first run z is 0. To fix this you should use calculate the length of inbuf and store it in a local variable before each conversion.
It is described here: http://www.gnu.org/s/libiconv/documentation/libiconv/iconv.3.html
And since you tagged this as C++ I would suggest wrapping everything up in a nice little class, as far as I can tell from the documentation you can reuse the inconv_t gained from iconv_open for as many conversions as you'd like.
#include <iconv.h>
#include <iostream>
#include <stdio.h>
#include <string.h>
using namespace std;
const size_t BUF_SIZE = 1024;
size_t z = (size_t) BUF_SIZE-1;
class IConv {
iconv_t ic_;
public:
IConv(const char* to, const char* from)
: ic_(iconv_open(to,from)) { }
~IConv() { iconv_close(ic_); }
bool convert(char* input, char* output, size_t outbufsize) {
size_t inbufsize = strlen(input);
return iconv(ic_, &input, &inbufsize, &output, &outbufsize);
}
};
int main(void)
{
char hello[BUF_SIZE] = "hello";
char bye[BUF_SIZE] = "bye";
char tmp[BUF_SIZE] = "something else";
IConv ic("UTF8","SJIS");
ic.convert(hello, tmp, BUF_SIZE);
cout << tmp << endl;
ic.convert(bye, tmp, BUF_SIZE);
cout << tmp << endl;
}