I wrote a program which perform string compression using counts of repeated characters. The program in C++ is :
#include<iostream>
#include<cstring>
std::string compressBad(std::string str)
{
std::string mystr = "";
int count = 1;
char last = str[0];
for (int i = 0; i < str.length();++i)
{
if(str[i] == last)
count++;
else
{
std::string lastS = last+"";
std::string countS = std::to_string(count);
mystr.append(lastS);
mystr.append(countS);
//mystr = mystr + last + count;
count = 1;
last = str[i];
}
}
std::string lastS = last+"";
std::string countS = std::to_string(count);
mystr.append(lastS);
mystr.append(countS);
return mystr;
//return mystr+last+count;
}
int main()
{
std::string str;
std::getline(std::cin, str);
std::string str2 = compressBad(str);
std::cout<<str2;
/*if (str.length() < str2.length())
std::cout<<str;
else
std::cout<<str2;*/
std::cout<<std::endl;
return 0;
}
Few example on running this are :
Input : sssaaddddd
Output : ùÿÿ*425
Output it should print : s3a2d5
Second example:
Input : sssaaddd
Output: ùÿÿ*423
Output it should print : s3a2d3
I also implemented the same concept in Java and there it is working fine. The java implementation is here
Why is this problem happening with above code.
There may be other issues in your code, but I think that this line might be to blame:
std::string lastS = last+"";
Here, you're trying to convert the character last to a string by concatenating the empty string to the end. Unfortunately, in C++ this is interpreted to mean "take the numeric value of the character last, then add that to a pointer that points to the empty string, producing a new pointer to a character." This pointer points into random memory, hence the garbage you're seeing. (Notice that this is quite different from how Java works!)
Try changing this line to read
std::string lastS(1, last);
This will initialize lastS to be a string consisting of just the character stored in last.
Another option would be to use an ostringstream:
std::ostringstream myStr;
myStr << last << count;
// ...
return myStr.str();
This eliminates all the calls to .append() and std::to_string and is probably a lot easier to read.
last + "" doesn't do what you think.
just do
mystr.append(1, last);
I am trying to find a string which is inside 2D char array and return it's index. For example:
char idTable[255][32];
char tester[] = { 't','e','s','t','e','r','\0' };
memcpy(idTable[43], tester, 7);
uint8_t id = getID(name[0]);
//name is returned from function "char **name = func();"
//but I have the same results when I try using normal char array...
I've had partial success with the first part of the below code, but it is finding a match if a part of the word is the same (one, oneTwo). If I add "else if" to the first "if" it always goes to the "else if".
The rest of the file prints different results for
printf("idTable string lenght:\t %u\n", strlen(idTable[index]));
and
printf("foundMatch string lenght:\t %u\n", strlen(foundMatch));
, unless I add printf("Index:\t %i\n", index);.
uint8_t getID(char *name) {
printf("\nInserted name:\t %s\n", name);
uint8_t index;
for (uint8_t r = 0; r < 255; r++) {
if (strstr(idTable[r], name) != NULL) {
printf("Found '%s' in position:\t %d\n", name, r);
index = r;
}
}
printf("Index:\t %i\n", index); // THIS LINE
char foundMatch[strlen(idTable[index])];
printf("idTable string lenght:\t %u\n", strlen(idTable[index]));
for (uint8_t c=0; c<strlen(idTable[index]); c++) {
foundMatch[c] = idTable[index][c];
}
printf("foundMatch string lenght:\t %u\n", strlen(foundMatch));
if (strcmp(foundMatch, nodeName) == 0) {
printf("Confirmed\n");
return index;
} else {
printf("Second test failed\n");
return 0;
}
}
Why am I getting this strange results and is there a better way to do this?
I don't know how you are initializing your idTable entries, but if you are using the method that you showed at the start of the question you'll have problems. You can't assume all of the space reserved by idTable is initialed to 0's, so idTable[43] isn't a null terminated string. Therefore idTable[43] need not compare equal to the null terminated string "tester".
Also your getID function doesn't return anything despite its signature. So it won't even compile as-is.
Here's a solution in actual C++, not C.
std::array<std::string, 255> idTable;
idTable.at(43) = "tester";
std::pair<std::size_t, std::size_t> findInIdTable(std::string const& what) {
for (unsigned i = 0; i < idTable.size(); ++i) {
std::size_t pos = idTable.at(i).find(what);
if (pos != std::string::npos) {
return std::make_pair(i, pos);
}
}
// if the code reaches this place, it means "not found". Choose how you want to deal with it
// my personal suggestion would be to return std::optional<std::pair<...> instead.
}
If you want to discard the pos value, it's easy to change as well.
Live On Coliru
In the category: Use C++
Of course, use std::array<char, 32> or std::string if possible. I stuck with your choices for this answer:
Live On Coliru
#include <algorithm>
#include <iostream>
#include <cstring>
char idTable[255][32] = { };
int main() {
using namespace std;
// initialize an entry
copy_n("tester", 7, idTable[43]);
// find match
auto match = [](const char* a) { return strcmp(a, "tester") == 0; };
auto index = find_if(begin(idTable), end(idTable), match) - idTable;
// print result
cout << "match at: " << index;
}
Prints
match at: 43
You need to add a nul to the end of the foundMatch array after copying in the idTable row:
foundMatch[strlen(idTable[index])] = '\0';
right before the 'foundMatch string lenght' (length) message.
strlen is an expensive function that walks the string every time. You should call that once, store it in a local variable, then reference that variable rather than calling strlen repeatedly.
Let say you have a string:
std::string s = "ABCD\t1234";
I can use std::string::find to get an offset to the '\t' character, but as far as I know there are no functions with the following signature:
int atoi_n(char *, int len);
An I missing anything? strtok replaces the \t with \0, and I don't want to touch the original buffer. I find it hard to believe that there aren't instances of the atoi, atof, etc which take a length parameter, but I can't find anything.
Anyone know if there is something I'm missing? I know boost has some tokenizers but I'd like avoid having to add the dependency of boost.
Looking the comments so far I'd like to clarify. Let's change the scenario:
char buffer[1024];
char *pStartPos;
char *pEndPost;
pStartPos = buffer + 5;
pEndPos = buffer + 10;
Let's also say you can't make any assumptions about the memory outside pStartPos and pEndPos. How do you convert the charaters between pStartPos and pEndPos to an int without adding a '\0' to buffer or copying using substr?
If you want to parse only the end of the string (from the character after \t to the end) you just need to pass a pointer to the first character to parse to atoi...
int n = atoi(s.c_str()+s.find('\t')+1);
(error checking omitted for brevity - in particular, we are always assuming that a \t is actually present)
If, instead, you want to parse from the beginning of the string up to \t you can just do
int n = atoi(s.c_str());
since atoi stops at the first non-numeric character anyway.
By the way, you should consider using more robust solutions for parsing the number, like strtol, sscanf or the C++ streams - they all can report a parsing error in some way, while atoi just returns 0 (which isn't distinguishable from a 0 that comes from parsing the string).
Incidentally, atoi is not in the "STL" by any means - it's just part of the C standard library.
I know that atoi is not in the STL. I was wondering if there was anything in STL like it where you can specify the last character which you want to include in the conversion. Basically I have a buffer which may be partially filled with garbage. I know the start of possible valid data and the end of possible valid data. I don't want to depend on whitespace to end the conversion, I want to be explicit about the length of the "field" because it also may not be /0 terminated.
If you are sure that the garbage doesn't start with digits you can use atoi/strtol/istringstream as is - they automatically stop just when they see the garbage. Otherwise, use the substr method to extract the exact substring you need:
std::string mayContainGarbage="alcak123456amaclmò";
std::string onlyTheDigits=mayContainGarbage.substr(5, 6);
// now parse onlyTheDigits as you prefer
To my knowledge, there is no such function out-of-box, but it shouldn't be difficult to implement.
For example:
template <typename ForwardIterator>
int range_to_int(ForwardIterator begin, ForwardIterator past_end) {
if (begin != past_end) {
bool negative = false;
auto ch = *begin;
if (ch == '-') {
negative = true;
++begin;
}
else if (ch == '+')
++begin;
if (begin != past_end) {
int result = 0;
do {
auto ch = *begin;
if (ch < '0' || ch > '9')
throw std::invalid_argument("Invalid digit.");
result = result * 10 + (ch - '0');
++begin;
} while (begin != past_end);
if (negative)
result = -result;
return result;
}
throw std::invalid_argument("+ or - must be followed by at least one digit.");
}
throw std::invalid_argument("Empty range.");
}
And you can use it like this:
int main() {
const char* buffer = "abc-123def";
int i = range_to_int(buffer + 4, buffer + 7);
assert(i == 123);
i = range_to_int(buffer + 3, buffer + 7);
assert(i == -123);
try {
i = range_to_int(buffer + 3, buffer + 8);
assert(false);
}
catch (const std::exception& ex) {
std::cout << ex.what() << std::endl;
}
try {
i = range_to_int(buffer + 3, buffer + 4);
assert(false);
}
catch (const std::exception& ex) {
std::cout << ex.what() << std::endl;
}
try {
i = range_to_int(buffer + 4, buffer + 4);
assert(false);
}
catch (const std::exception& ex) {
std::cout << ex.what() << std::endl;
}
// You can use it on std::string as well....
const std::string str = buffer;
i = range_to_int(str.begin() + 4, str.begin() + 7);
assert(i == 123);
// Etc...
return EXIT_SUCCESS;
}
i need to create a function that will accept a directory path. But in order for the compiler to read backslash in i need to create a function that will make a one backslash into 2 backslash.. so far this are my codes:
string stripPath(string path)
{
char newpath[99999];
//char *pathlong;
char temp;
strcpy_s(newpath, path.c_str());
//pathlong = newpath;
int arrlength = sizeof(newpath);
for (int i = 0; i <= arrlength ;i++)
{
if(newpath[i] == '\\')
{
newpath[i] += '\\';
i++;
}
}
path = newpath;
return path;
}
this code receives an input from a user which is a directory path with single backslash.
the problem is it gives a dirty text output;
int arrlength = sizeof(newpath); causes the size of your entire array (in chars) to be assigned to arrlength. This means you are iterating over 99999 characters in the array, even if the path is shorter (which it probably is).
Your loop condition also allows goes one past the bounds of the array (since the last (99999th) element is actually at index 99998, not 99999 -- arrays are zero-based):
for (int i = 0; newpath[i]] != '\0'; i++)
Also, there is no reason to copy the string into a character array first, when you can loop over the string object directly.
In any case, there is no need to escape backslashes from user input. The backslash is a single character like any other; it is only special when embedded in string literals in your code.
In this line:
if(newpath[i] = '\\')
replace = with ==.
In this line:
newpath[i] += '\\';
This is supposed to add a \ into the string (I think that's what you want), but it actually does some funky char math on the current character. So instead of inserting a character, you are corrupting the data.
Try this instead:
#include <iostream>
#include <string>
#include <sstream>
int main(int argc, char ** argv) {
std::string a("hello\\ world");
std::stringstream ss;
for (int i = 0; i < a.length(); ++i) {
if (a[i] == '\\') {
ss << "\\\\";
}
else {
ss << a[i];
}
}
std::cout << ss.str() << std::endl;
return 0;
}
lots wrong. did not test this but it will get you closer
http://www.cplusplus.com/reference/string/string/
string stripPath(string path)
{
string newpath;
for (int i = 0; i <= path.length() ;i++)
{
if(path.at(i) == '\\')
{
newpath.append(path.at(i));
newpath.append(path.at(i));
}
else
newpath.append(path.at(i));
}
return newpath;
}
But in order for the compiler to read
backslash in i need to create a
function that will make a one
backslash into 2 backslash
The compiler only reads string when you compile, and in that case you will need two as the first back slash will be an escape character. So if you were to have a static path string in code you would have to do something like this:
std::string path = "C:\\SomeFolder\\SomeTextFile.txt";
The compiler will never actually call your function only compile it. So writing a function like this so the compiler can read a string is not going to solve your problem.
The condition if (newpath[i] = '\\') should be if (newpath[i] == '\\').
The statement newpath[i] += '\\'; will not give the intended result of concatenation. It will instead add the integral value of '\\' to newpath[i].
Moreover why are you using a char newpath[99999]; array inside the function. newpath could be std::string newpath.
int main()
{
std::string path = "c:\\test\\test2\\test3\\test4";
std::cout << "orignal path: " << path << std::endl;
size_t found = 0, next = 0;
while( (found = path.find('\\', next)) != std::string::npos )
{
path.insert(found, "\\");
next = found+4;
}
std::cout << "path with double slash: " << path << std::endl;
return 0;
}
What is the effective way to replace all occurrences of a character with another character in std::string?
std::string doesn't contain such function but you could use stand-alone replace function from algorithm header.
#include <algorithm>
#include <string>
void some_func() {
std::string s = "example string";
std::replace( s.begin(), s.end(), 'x', 'y'); // replace all 'x' to 'y'
}
The question is centered on character replacement, but, as I found this page very useful (especially Konrad's remark), I'd like to share this more generalized implementation, which allows to deal with substrings as well:
std::string ReplaceAll(std::string str, const std::string& from, const std::string& to) {
size_t start_pos = 0;
while((start_pos = str.find(from, start_pos)) != std::string::npos) {
str.replace(start_pos, from.length(), to);
start_pos += to.length(); // Handles case where 'to' is a substring of 'from'
}
return str;
}
Usage:
std::cout << ReplaceAll(string("Number Of Beans"), std::string(" "), std::string("_")) << std::endl;
std::cout << ReplaceAll(string("ghghjghugtghty"), std::string("gh"), std::string("X")) << std::endl;
std::cout << ReplaceAll(string("ghghjghugtghty"), std::string("gh"), std::string("h")) << std::endl;
Outputs:
Number_Of_Beans
XXjXugtXty
hhjhugthty
EDIT:
The above can be implemented in a more suitable way, in case performance is of your concern, by returning nothing (void) and performing the changes "in-place"; that is, by directly modifying the string argument str, passed by reference instead of by value. This would avoid an extra costly copy of the original string by overwriting it.
Code :
static inline void ReplaceAll2(std::string &str, const std::string& from, const std::string& to)
{
// Same inner code...
// No return statement
}
Hope this will be helpful for some others...
I thought I'd toss in the boost solution as well:
#include <boost/algorithm/string/replace.hpp>
// in place
std::string in_place = "blah#blah";
boost::replace_all(in_place, "#", "#");
// copy
const std::string input = "blah#blah";
std::string output = boost::replace_all_copy(input, "#", "#");
Imagine a large binary blob where all 0x00 bytes shall be replaced by "\1\x30" and all 0x01 bytes by "\1\x31" because the transport protocol allows no \0-bytes.
In cases where:
the replacing and the to-replaced string have different lengths,
there are many occurences of the to-replaced string within the source string and
the source string is large,
the provided solutions cannot be applied (because they replace only single characters) or have a performance problem, because they would call string::replace several times which generates copies of the size of the blob over and over.
(I do not know the boost solution, maybe it is OK from that perspective)
This one walks along all occurrences in the source string and builds the new string piece by piece once:
void replaceAll(std::string& source, const std::string& from, const std::string& to)
{
std::string newString;
newString.reserve(source.length()); // avoids a few memory allocations
std::string::size_type lastPos = 0;
std::string::size_type findPos;
while(std::string::npos != (findPos = source.find(from, lastPos)))
{
newString.append(source, lastPos, findPos - lastPos);
newString += to;
lastPos = findPos + from.length();
}
// Care for the rest after last occurrence
newString += source.substr(lastPos);
source.swap(newString);
}
A simple find and replace for a single character would go something like:
s.replace(s.find("x"), 1, "y")
To do this for the whole string, the easy thing to do would be to loop until your s.find starts returning npos. I suppose you could also catch range_error to exit the loop, but that's kinda ugly.
For completeness, here's how to do it with std::regex.
#include <regex>
#include <string>
int main()
{
const std::string s = "example string";
const std::string r = std::regex_replace(s, std::regex("x"), "y");
}
If you're looking to replace more than a single character, and are dealing only with std::string, then this snippet would work, replacing sNeedle in sHaystack with sReplace, and sNeedle and sReplace do not need to be the same size. This routine uses the while loop to replace all occurrences, rather than just the first one found from left to right.
while(sHaystack.find(sNeedle) != std::string::npos) {
sHaystack.replace(sHaystack.find(sNeedle),sNeedle.size(),sReplace);
}
As Kirill suggested, either use the replace method or iterate along the string replacing each char independently.
Alternatively you can use the find method or find_first_of depending on what you need to do. None of these solutions will do the job in one go, but with a few extra lines of code you ought to make them work for you. :-)
What about Abseil StrReplaceAll? From the header file:
// This file defines `absl::StrReplaceAll()`, a general-purpose string
// replacement function designed for large, arbitrary text substitutions,
// especially on strings which you are receiving from some other system for
// further processing (e.g. processing regular expressions, escaping HTML
// entities, etc.). `StrReplaceAll` is designed to be efficient even when only
// one substitution is being performed, or when substitution is rare.
//
// If the string being modified is known at compile-time, and the substitutions
// vary, `absl::Substitute()` may be a better choice.
//
// Example:
//
// std::string html_escaped = absl::StrReplaceAll(user_input, {
// {"&", "&"},
// {"<", "<"},
// {">", ">"},
// {"\"", """},
// {"'", "'"}});
#include <iostream>
#include <string>
using namespace std;
// Replace function..
string replace(string word, string target, string replacement){
int len, loop=0;
string nword="", let;
len=word.length();
len--;
while(loop<=len){
let=word.substr(loop, 1);
if(let==target){
nword=nword+replacement;
}else{
nword=nword+let;
}
loop++;
}
return nword;
}
//Main..
int main() {
string word;
cout<<"Enter Word: ";
cin>>word;
cout<<replace(word, "x", "y")<<endl;
return 0;
}
Old School :-)
std::string str = "H:/recursos/audio/youtube/libre/falta/";
for (int i = 0; i < str.size(); i++) {
if (str[i] == '/') {
str[i] = '\\';
}
}
std::cout << str;
Result:
H:\recursos\audio\youtube\libre\falta\
For simple situations this works pretty well without using any other library then std::string (which is already in use).
Replace all occurences of character a with character b in some_string:
for (size_t i = 0; i < some_string.size(); ++i) {
if (some_string[i] == 'a') {
some_string.replace(i, 1, "b");
}
}
If the string is large or multiple calls to replace is an issue, you can apply the technique mentioned in this answer: https://stackoverflow.com/a/29752943/3622300
here's a solution i rolled, in a maximal DRI spirit.
it will search sNeedle in sHaystack and replace it by sReplace,
nTimes if non 0, else all the sNeedle occurences.
it will not search again in the replaced text.
std::string str_replace(
std::string sHaystack, std::string sNeedle, std::string sReplace,
size_t nTimes=0)
{
size_t found = 0, pos = 0, c = 0;
size_t len = sNeedle.size();
size_t replen = sReplace.size();
std::string input(sHaystack);
do {
found = input.find(sNeedle, pos);
if (found == std::string::npos) {
break;
}
input.replace(found, len, sReplace);
pos = found + replen;
++c;
} while(!nTimes || c < nTimes);
return input;
}
I think I'd use std::replace_if()
A simple character-replacer (requested by OP) can be written by using standard library functions.
For an in-place version:
#include <string>
#include <algorithm>
void replace_char(std::string& in,
std::string::value_type srch,
std::string::value_type repl)
{
std::replace_if(std::begin(in), std::end(in),
[&srch](std::string::value_type v) { return v==srch; },
repl);
return;
}
and an overload that returns a copy if the input is a const string:
std::string replace_char(std::string const& in,
std::string::value_type srch,
std::string::value_type repl)
{
std::string result{ in };
replace_char(result, srch, repl);
return result;
}
This works! I used something similar to this for a bookstore app, where the inventory was stored in a CSV (like a .dat file). But in the case of a single char, meaning the replacer is only a single char, e.g.'|', it must be in double quotes "|" in order not to throw an invalid conversion const char.
#include <iostream>
#include <string>
using namespace std;
int main()
{
int count = 0; // for the number of occurences.
// final hold variable of corrected word up to the npos=j
string holdWord = "";
// a temp var in order to replace 0 to new npos
string holdTemp = "";
// a csv for a an entry in a book store
string holdLetter = "Big Java 7th Ed,Horstman,978-1118431115,99.85";
// j = npos
for (int j = 0; j < holdLetter.length(); j++) {
if (holdLetter[j] == ',') {
if ( count == 0 )
{
holdWord = holdLetter.replace(j, 1, " | ");
}
else {
string holdTemp1 = holdLetter.replace(j, 1, " | ");
// since replacement is three positions in length,
// must replace new replacement's 0 to npos-3, with
// the 0 to npos - 3 of the old replacement
holdTemp = holdTemp1.replace(0, j-3, holdWord, 0, j-3);
holdWord = "";
holdWord = holdTemp;
}
holdTemp = "";
count++;
}
}
cout << holdWord << endl;
return 0;
}
// result:
Big Java 7th Ed | Horstman | 978-1118431115 | 99.85
Uncustomarily I am using CentOS currently, so my compiler version is below . The C++ version (g++), C++98 default:
g++ (GCC) 4.8.5 20150623 (Red Hat 4.8.5-4)
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
This is not the only method missing from the standard library, it was intended be low level.
This use case and many other are covered by general libraries such as:
POCO
Abseil
Boost
QtCore
QtCore & QString has my preference: it supports UTF8 and uses less templates, which means understandable errors and faster compilation. It uses the "q" prefix which makes namespaces unnecessary and simplifies headers.
Boost often generates hideous error messages and slow compile time.
POCO seems to be a reasonable compromise.
How about replace any character string with any character string using only good-old C string functions?
char original[256]="First Line\nNext Line\n", dest[256]="";
char* replace_this = "\n"; // this is now a single character but could be any string
char* with_this = "\r\n"; // this is 2 characters but could be of any length
/* get the first token */
char* token = strtok(original, replace_this);
/* walk through other tokens */
while (token != NULL) {
strcat(dest, token);
strcat(dest, with_this);
token = strtok(NULL, replace_this);
}
dest should now have what we are looking for.