How do you use string.erase and string.find? - c++

Why cant i call string.find in string.erase like so: str.erase(str.find(a[1]),str.size())?
edit:code added
#include "stdafx.h"
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
// html tags
string tags[5]={"<!--...-->","<!DOCTYPE>","<a>","<abbr>","<acronym>"};
//
//check if string exists
int boolStringExists(string a, string b)
{
if(a.find(b)>0)
{
return 1;
}
if(a.find(b)<=0)
{
return 0;
}
}
//erase tag from string a
void eraseTags(string a,string b[])
{
for(int i=0; i<5;i++)
{
int x=(boolStringExists(a,b[i]));
while (x>0)
{
a.erase(a.find(b[i]),b[i].size());
x=(boolStringExists(a,b[i]));
}
}
}
int _tmain(int argc, _TCHAR* argv[])
{
fstream file;
file.open("h:\\a.htm");
string k,m;
while(getline(file, k))
m += k ;
eraseTags(m,tags);
return 0;
}
Gives this message: "this application has requested the runtime to terminate it in an unusual way.Please contact the application's support team for more information."

If the string is not found, find returns string::npos, and then your code wouldn't work and will give runtime error. See this gives error : https://ideone.com/NEhqn
So better write this:
size_t pos = str.find(a[1]);
if ( pos != std::string::npos)
str.erase(pos); //str.size() is not needed!
Now this doesn't give error : https://ideone.com/IF2Hy

There's nothing wrong with that call (assuming a[1] exists and is found in str at least once)
#include <iostream>
#include <string>
int main()
{
std::string str = "Hello, world!";
std::string a = "wwwwww";
str.erase(str.find(a[1]), str.size());
std::cout << str << '\n';
}
test run: https://ideone.com/8wibR
EDIT: Your full source code fails to check if b[1] is actually found in str. The function boolStringExists() returns 1 if a.find(b) is greater than zero, and the value of std::string::npos which it returns when b is not found in a IS greater than zero.
To fix this while keeping the rest of your logic intact, change that function to
//check if string exists
bool boolStringExists(string a, string b)
{
return a.find(b) != string::npos;
}

It seems you want to erase everything that comes after str.find(a[1]). In that case you can omit the second argument.
#include <iostream>
#include <string>
int main(int argc, char *argv[]) {
std::string str = "Hello, world!";
std::string needle = "o,";
str.erase(str.find(needle));
std::cout << str << "\n";
}
In this example I used needle instead of a[1], but the principle is the same.

Related

i am trying to use getline to read a csv file line by line and separate the data in the file and turn a string into int

I am a beginner and I just need a bit of help on why I getline is showing an error:
this is what I have so far
#include <iostream>
#include <iomanip>
#include <cmath>
#include <fstream>
using namespace std;
const double TAX_RATE = 0.0825;
const int MAX_ITEMS = 1000;
const int MAX_TRANSACTIONS = 100;
int main(int argc, char const *argv[]){
string fname = "";
int itemCnt = 0, start = 0, end = 0;
int ids[MAX_ITEMS], qtys[MAX_ITEMS];
double costs[MAX_ITEMS], subtotals[MAX_TRANSACTIONS],
taxes[MAX_TRANSACTIONS], totals[MAX_TRANSACTIONS];
string names[MAX_ITEMS], paymentTypes[MAX_ITEMS], payments[MAX_ITEMS];
ifstream iFile;
if ( argc != 2 ) {
cout<<"usage: "<< argv[0]<< " <file name>" <<endl;
return 0;
} else {
iFile.open(argv[1]);
}
if (!iFile) {
cout<<"Error: Invalid file name"<<endl;
cin.clear();
}
while (!iFile.eof())
{
getline(iFile,str); //this isn't working
int commaLoc = str.find(',');
ids[itemCnt]= str.substr(0,commaLoc);
str = str.substr(commaLoc +1, str.length());
//string to int I'm not sure how to do I know its something with stoi() but not sure how to format it
}
return 0;
}
I am able to get the file to open but I'm not sure why getline isn't working it keeps saying something like
no instance of overload function
My csv file looks like:
1,Laptop,799.99,1,cash,1100
I need it to read the first number and because Its a string i don't know how to save it as an int
Multiple errors. First there is nothing called 'str' in your program. I will guess its just a string used as a temp buffer
do not do this (!File.eof) it doesnt do what you think.
while (iFile)
{
string str; <<<<<==== added
getline(iFile,str); //this isn't working <<<===is now
int commaLoc = str.find(',');
Next this line doesnt work because ids are ints and substring returns a string.
// ids[itemCnt]= str.substr(0,commaLoc);
ids[itemCnt]= stoi(str.substr(0,commaLoc)); <<<<==== fixed
str = str.substr(commaLoc +1, str.length());
}
I strongly recommend you use std::vector instead of c-style fixed size arrays. Takes 5 minutes to learn how to use them and they have huge benefits. If you must use fixed size arrays use std::array instead of c-style
You can read a string and try to convert it to a number in different ways. For example, since C++17, you can use from_chars. One of its overloads:
Receives a pair of begin and end char pointers, and an int variable,
tries to parse an int number, and
and returns the parsed number, together with a pointer to the first character that wasn't part of the match.
int i{};
auto [ptr, ec] = std::from_chars(str.data(), str.data() + str.size(), i);
if (ec == std::errc{}) { /* do something with i */} else { /* error */ }
[Demo]
Full code (using a istrinstream instead of a ifstream):
#include <charconv> // from_chars
#include <iomanip>
#include <iostream>
#include <sstream> // istringstream
#include <system_error> // errc
constinit const int MAX_ITEMS = 10;
int main() {
std::istringstream iss{
"1,Laptop,799.99,1,cash,1100\n"
"2,PC,688.88,2,card,1101\n"
"blah,Keyboard,39.00,3,cash,1102"
};
size_t itemCnt{};
int ids[MAX_ITEMS]{};
std::string str{};
while (std::getline(iss, str)) {
// Parse counter
int i{};
auto [ptr, ec] = std::from_chars(str.data(), str.data() + str.size(), i);
if (ec == std::errc{}) {
ids[itemCnt] = i;
// Remaining string
std::string remaining_string{ str.substr(ptr - str.data() + 1) };
std::cout << ids[itemCnt] << ", " << remaining_string << "\n";
}
else {
std::cout << "Error: invalid counter.\n";
}
++itemCnt;
}
}
// Outputs:
//
// 1, Laptop,799.99,1,cash,1100
// 2, PC,688.88,2,card,1101
// Error: invalid counter.

Got stuck in C++ infinite loop

I'm doing a leetcode challenge to practice my c++
I am supposed to replace all the "." from an ip address to "[.]"
so essentially, x.x.x.x is supposed to become x[.]x[.]x[.]x
My code is :
#include <iostream>
#include <string.h>
using namespace std;
int main(int argc, const char * argv[]) {
string address ="1.1.1.1";
while(address.find(".") != string::npos){
address.replace(address.find("."), 1,"[.]");
}
cout<<address<<endl;
}
However, I am getting stuck in a loop where it is doing :
x.x.x.x
x[.]x.x.x
x[[.]]x.x.x
x[[[.]]]x.x.x
and so on.
How do I get out of this loop? Thank you!
You can specify where to start by the 2nd argument of std::string::find.
#include <iostream>
#include <string>
int main(int argc, const char * argv[]) {
std::string address ="1.1.1.1";
std::string::size_type start_pos = 0, current_pos;
while((current_pos = address.find(".", start_pos)) != std::string::npos){
address.replace(current_pos, 1,"[.]");
start_pos = current_pos + 3; // start next search after the inserted string
}
std::cout<<address<<std::endl;
}
Learn to separate code into functions (this is important). Also it is easier to store result into separate variable, so you do not have to update search point.
std::string escapeDots(const std::string& s)
{
std::string result;
result.reserve(s.size() + 8);
for (auto ch : s) {
if (ch == '.')
result += "[.]";
else
result += ch;
}
return result;
}
This code is more clear the alternative answer and most probably is faster.
With <regex>, it would be
int main()
{
std::string address = "1.1.1.1";
std::cout << std::regex_replace(address, std::regex("\\."), "[.]") << std::endl;
}
Demo.

C++ segmentation fault while counting character occurrences in string

I've written a simple function to count occurrences of a character in a string. The compiler is fine. However, as I try to run it, it produced a segmentation fault.
#include <iostream>
using namespace std;
// To count the number of occurences of x in p
// p is a ะก-style null-terminated string
int count_x(char* p, char x)
{
if (p == nullptr)
{
return 0;
}
// start the counter
int count = 0;
while (p != nullptr)
{
if (*p == x)
{
++count;
}
}
return count;
}
int main(int argc, char const *argv[])
{
char myString[] = "Hello";
cout << count_x(myString, 'l');
return 0;
}
There's two mistakes in your code:
You only ever look at the first character in the string.
The last character of a null terminated string is a null character. You're testing the pointer itself.
You need to use std::string
#include <string>
#include <algorithm>
#include <iostream>
int main()
{
std::string str = "Hello";
std::cout << std::count(str.begin(), str.end(), 'l');
}

Putting String array in parameter, then comparing the elements to literal strings error?

Let's say I have an array
string test = {"test1, "test2"}
I have my function
void testing(string test){
for(int i = 0; i < 2; i++){
if(test[i] == "test1"){
cout << "success" << endl;
}
}
}
But when I compile this, I get an error...why is that?
Is there a different approach?
Your test variable should be declared as an array type
string test[] = {"test1", "test2"};
You also need to change the function signature from
void testing(string test)
to
void testing(string* test){
the code you wrote is not going to compile because of wrong declaration of string array.
replace
string test = {"test1, "test2"};
with
string test[]={"test1, "test2"};
The following code uses the array in place without function
#include <iostream>
#include <string>
using namespace std;
string test[]={"test1, "test2"};
for(auto& item:test)
{
cout<<item<<endl;
}
I think the best way to get this working with function is to use vector
#include <iostream>
#include <string>
#include <vector>
using namespace std;
void testing(const vector<string>& strings)
{
for (auto& item : strings)
{
cout << item << endl;
}
}
int _tmain(int argc, _TCHAR* argv[])
{
vector<string> strings = { "str1", "str2", "str3" };
testing(strings);
cin.get();
return 0;
}

How to run multiple arguments in Cygwin

I've been trying to run a program that will invert the order of a string and to run it, I have to type a second argument in prompt.
int main(int argc, char* argv[])
{
string text = argv[2];
for (int num=text.size(); num>0; num--)
{
cout << text.at(num);
}
return 0;
}
e.g. ./program lorem result: merol
#include <iostream>
#include <string>
using namespace std;
int main(int argc, char* argv[])
{
string text = argv[1];
for (int num=text.size() - 1; num >= 0; num--)
{
cout << text.at(num);
}
return 0;
}
You missed the includes and used string::at wrong. There are size() chars in the string but you start counting at 0. Then the loop has to run until num >= 0 and not num > 0. You also used the wrong index into argv.
This would still be an abomination of C++. A clearer way would be:
#include <iostream>
#include <string>
#include <algorithm>
int main(int argc, char* argv[])
{
std::string text = argv[1];
for(std::string::reverse_iterator it = text.rbegin(); it != text.rend(); ++it) {
std::cout << *it;
}
std::cout << std::endl;
//or if you want further usage of the reversed string
std::reverse(text.begin(), text.end());
std::cout << text;
return 0;
}
I think you're getting an exception because num is out of bounds. size() is returning a value one larger than the biggest valid index into the string, so at() is throwing an exception.