I am a beginner at coding, and was trying this question that replaces all repetitions of a letter in a string with a hyphen: i.e ABCDAKEA will become ABCD-KE-.I used the switch loop and it works, but i want to make it shorter and maybe use recursion to make it more effective. Any ideas?
#include<iostream>
#include<string.h>
using namespace std;
int main()
{
char x[100];
int count[26]={0}; //initialised to zero
cout<<"Enter string: ";
cin>>x;
for(int i=0; i<strlen(x); i++)
{
switch(x[i])
{
case 'a':
{
if((count[0]++)>1)
x[i]='-';
}
case 'b':
{
if((count[1]++)>1)
x[i]='-';
}
case 'c':
{
if((count[2]++)>1)
x[i]='-';
}
//....and so on for all alphabets, ik not the cutest//
}
}
Iterate through the array skipping whitespace, and put characters you've never encountered before in std::set, if you find them again you put them in a duplicates std::set if you'd like to keep track of how many duplicates there are, otherwise change the value of the original string at that location to a hyphen.
#include <iostream>
#include <string>
#include <cctype>
#include <set>
int main() {
std::string s("Hello world");
std::set<char> characters;
std::set<char> duplicates;
for (std::string::size_type pos = 0; pos < s.size(); pos++) {
char c = s[pos];
// std::isspace() accepts an int, so cast c to an int
if (!std::isspace(static_cast<int>(c))) {
if (characters.count(c) == 0) {
characters.insert(c);
} else {
duplicates.insert(c);
s[pos] = '-';
}
}
}
return 0;
}
Naive (inefficient) but simple approach, requires at least C++11.
#include <algorithm>
#include <cctype>
#include <iostream>
#include <string>
std::string f(std::string s)
{
auto first{s.begin()};
const auto last{s.end()};
while (first != last)
{
auto next{first + 1};
if (std::isalpha(static_cast<unsigned char>(*first)))
std::replace(next, last, *first, '-');
first = next;
}
return s;
}
int main()
{
const std::string input{"ABCDBEFKAJHLB"};
std::cout << f(input) << '\n';
return 0;
}
First, notice English capital letters in ASCII table fall in this range 65-90. Casting a capital letter static_cast<int>('A') will yield an integer. If after casing the number is between 65-90, we know it is a capital letter. For small letters, the range is 97-122. Otherwise the character is not a letter basically.
Check create an array or a vector of bool and track the repetitive letters. Simple approach is
#include <iostream>
#include <string>
#include <vector>
using namespace std;
int main()
{
string str("ABCDAKEAK");
vector<bool> vec(26,false);
for(int i(0); i < str.size(); ++i){
if( !vec[static_cast<int>(str[i]) - 65] ){
cout << str[i];
vec[static_cast<int>(str[i]) - 65] = true;
}else{
cout << "-";
}
}
cout << endl;
return 0;
}
Note: I assume the input solely letters and they are capital. The idea is centered around tracking via bool.
When you assume input charactor encode is UTF-8, you can refactor like below:
#include <iostream>
#include <string>
#include <optional>
#include <utility>
std::optional<std::size_t> char_to_index(char u8char){
if (u8'a' <= u8char && u8char <= u8'z'){
return u8char - u8'a';
}
else if (u8'A' <= u8char && u8char <= u8'A'){
return u8char - u8'A';
}
else {
return std::nullopt;
}
}
std::string repalce_mutiple_occurence(std::string u8input, char u8char)
{
bool already_found[26] = {};
for(char& c : u8input){
if (const auto index = char_to_index(c); index && std::exchange(already_found[*index], true)){
c = u8char;
}
}
return u8input;
}
int main(){
std::string input;
std::getline(std::cin, input);
std::cout << repalce_mutiple_occurence(input, u8'-');
}
https://wandbox.org/permlink/UnVJHWH9UwlgT7KB
note: On C++20, you should use char8_t instead of using char.
Related
I was given a project in class and almost have it finished, I am required to take a string of numbers and letters and return that string with the numbers printed first followed by the letters in reverse order (ex. abc123 should return 123cba). As of now my code returns a string with the numbers first and the original order of the letters (ex. abc123 returns 123abc). I would be able to do this with two loops however the assignment asks that my code only iterates though the initial string one time. Here is the code I have so far...
#include <iostream>
#include <string>
#include "QueType.h"
#include "StackType.h"
using namespace std;
int main ()
{
QueType<char> myQueue;
StackType<char> myStack;
string myString="hello there123";
char curchar;
string numbers, letters;
for (int i = 0; i < myString.length(); i++) {
if (isdigit(myString.at(i))) {
myQueue.Enqueue(myString.at(i));
myQueue.Dequeue(curchar);
numbers += curchar;
//cout<<numbers<<endl;
}
else if (islower(myString.at(i))) {
myStack.Push(myString.at(i));
curchar = myStack.Peek();
myStack.Pop();
letters += curchar;
//cout<<curchar<<endl;
}
}
cout<<(myString = numbers + letters)<<endl;
}
In my code, I have two .h files that set up a stack and a queue. With the given string, the code loops through the string looking to see if it sees a letter or number. With a number the spot in the string is then saved to a queue, and with a letter it is saved to the stack.
The only other way i can think of reversing the order of the letters is in the if else statement instead of having char = myStack.Peek() every loop, change it to char += myStack.Peek() however I get weird lettering when that happens.
since you already got the string with letters you can basically reverse it and that's it.
//emplace version:
void reverse_str(std::string& in)
{
std::reverse(in.begin(), in.end());
}
//copy version
std::string reverse_str(std::string in)
{
std::reverse(in.begin(), in.end());
return in;
}
in your case the emplace version would be the best match.
in other cases (e.g. when you want to preserve the original string) the copy version is preferred.
adding an example to make it as clean as possible.
int main()
{
std::string inputstr = "123abc";
std::string numbers{};
std::string letters{};
for(auto c : inputstr)
{
if(isdigit(c))
numbers += c;
else
letters += c;
}
reverse_str(letters); //using the emplace version
std::cout << numbers + letters;
}
Here's my take. It only loops through the string once. I don't have your types, so I'm just using the std versions.
std::string output;
output.reserve( myString.size() );
std::stack<char> stack;
for ( char c : myString ) {
if ( std::isdigit( c ) ) // if it's a number, just add it to the output
output.push_back( c );
else // otherwise, add the character to the stack
stack.push( c );
}
// string is done being processed, so use the stack to get the
// other characters in reverse order
while ( !stack.empty() ) {
output.push_back( stack.top() );
stack.pop();
}
std::cout << output;
working example: https://godbolt.org/z/eMazcGsMf
Note: wasn't sure from your description how to handle characters other than letters and numbers, so treated them the same as letters.
One way to do this is as follows:
Version 1
#include <iostream>
#include <string>
int main() {
std::string s = "abc123";
std::string output;
output.resize(s.size());
int i = output.length() - 1;
int j = 0;
for(char &c: s)
{
if(!std::isdigit(c))
{
output.at(i) = c;
--i;
}
else
{
output.at(j) = c;
++j;
}
}
std::cout<<output<<std::endl;
}
You can also use iterators in the above program to obtain the desired result as shown in version 2.
Version 2
#include <iostream>
#include <string>
int main() {
std::string s = "abfsc13423";
std::string output;
output.resize(s.size());
std::string::reverse_iterator iter = output.rbegin();
std::string::iterator begin = output.begin();
for(char &c: s)
{
if(!std::isdigit(c))
{
*iter = c;
++iter;
}
else
{
*begin = c;
++begin;
}
}
std::cout<<output<<std::endl;
}
I've found plenty of resources online how how to calculate the sum of numbers in an alphanumeric string, and I've got a working c++ code below.
#include <iostream>
using namespace std;
int findSum(string str)
{
string temp = "";
int sum = 0;
for (char ch: str)
{
if (isdigit(ch))
temp += ch;
else
{
sum += atoi(temp.c_str());
temp = "";
}
}
return sum + atoi(temp.c_str());
}
int main()
{
string str = "t35t5tr1ng";
cout << findSum(str);
return 0;
}
For the example above, "t35t5tr1ng" returns "41".
Now I'm trying to do the same thing, without using any loops.
On the top of my head, I'm thinking arrays, but even then I'm not sure how to parse the values in the array without a for loop of some kind.
Any suggestions or help would be appreciated!
You can use standard algorithms instead of writing loops. Even if it's just a for-loop under the hood, but it can make user code easier to understandby stating the intent.
int findSum(string str)
{
// replace all the non-digits with spaces
std::replace_if(str.begin(), str.end(),
[](unsigned char c) {
return !std::isdigit(c);
}, ' ');
// sum up space separated numbers
std::istringstream iss{str};
return std::accumulate(
std::istream_iterator<int>{iss},
std::istream_iterator<int>{}, 0);
}
Here's a demo.
Here is another solution using std::accumulate:
#include <numeric>
#include <iostream>
#include <string>
#include <cctype>
int findSum(std::string str)
{
int curVal = 0;
return std::accumulate(str.begin(), str.end(), 0, [&](int total, char ch)
{
// build up the number if it's a digit
if (std::isdigit(static_cast<int>(ch)))
curVal = 10 * curVal + (ch - '0');
else
{
// add the number and reset the built up number to 0
total += curVal;
curVal = 0;
}
return total;
});
}
int main()
{
std::string str = "t35t5tr1ng";
std::cout << findSum(str);
return 0;
}
I'm using C++. So far, my code goes like this:
#include <stdio.h>
#include <conio.h>
#include <string.h>
#include <windows.h>
int main() {
char word[100]; int ctr, count = 0;
printf("Enter string: "); gets(word);
ctr = 1;
while (word[ctr] != '\0') {
if (word[ctr-1] == word[ctr]) count++;
ctr++;
}
printf("%d", count);
return 0;
}
Sample Run
Enter string: mississippi
3
Enter string: mmmmrrnzzz
6
I've got the first sample run correctly (mississippi) with only 3 characters appearing twice consecutively but not on the second sample run (mmmmrrnzzz) with output 6.
My problem is that, it should not be 6 but 4 instead. 1 for the first two consecutive m, another separate 1 for the next two consecutive m, 1 for r, and 1 for z. I want a separate count for the first "mm" and the second "mm" and also for the "zz" but I don't know how.
I'm a freshman and very new to programming. I wish I could explain better. I'm hoping you could help me. Thank you.
In case of multiple couples like mmmm you need to make a double incrementation of your counter:
#include <stdio.h>
#include <string.h>
int main()
{
char word[100];
int ctr;
int count = 0;
printf("Enter string: ");
gets(word);
int len = strlen(word);
ctr = 1;
while (ctr<len) {
if (word[ctr-1] == word[ctr])
{
count++;
ctr++;
}
ctr++;
}
printf("%d", count);
return 0;
}
First of all the program looks like a C program. In fact you are not using C++. You are using C.:) At least for example in C++ you should use header
#include <cstdio>
instead of
#include <stdio.h>
and so on.
And moreover it has a bug because in general the string can be empty. In this case the condition of the loop skips the first zero-terminating character and the program has undefined behaviour.
Here is a correct approach
#include <stdio.h>
int main( void )
{
const char *s = "mmmmrrnzzz";
size_t count = 0;
while ( *s++ )
{
if ( *s == *( s - 1) )
{
++count;
++s;
}
}
printf( "count = %zu\n", count );
}
The output is
count = 4
Take into account that function gets is unsafe and is not supported by the C (or C++) Standard any more.
You should use function fgets instead of gets.
This will work
#include <stdio.h>
#include <string.h>
int main() {
char word[100]; int ctr, count = 0;
printf("Enter string: "); gets(word);
int len=strlen(word);
ctr = 1;
while (ctr<len) {
if (word[ctr-1] == word[ctr])
{
count++;
ctr++;
}
ctr++;
}
printf("%d", count);
return 0;
}
A standard library version:
#include <algorithm>
#include <iostream>
#include <string>
int main()
{
int count{};
std::string s;
std::cin >> s;
for (auto it = s.begin(); (it = std::adjacent_find(it, s.end())) != s.end(); it += 2)
++count;
std::cout << count << '\n';
}
I am trying to code a program where it takes a program as an input and prints out all the comments written in that program in a separate line.
#include <cmath>
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
int main() {
string str;
while(getline(cin,str)) {
int i;
// cout<<str;
for(i=0;str[i]!='/' && str[i+1] !='/';i++);
//cout<<i;
for(i;str[i]!='\n';i++) {
// cout<<i;
cout<<str[i];
}
cout<<endl;
}
return 0;
}
I am getting a segmentation fault in this code and I can't understand why. This is part of a code of a problem in hackerrank https://www.hackerrank.com/challenges/ide-identifying-comments/copy-from/12957153
As commented in your question your code is wrong. First you are treating std::string object, returned by getline, as character array. Secondly your for loops never end if there is no // or \n found in input string. So obviously it will crash. Below is the modified code.
#include <cmath>
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
int main() {
string str;
while(getline(cin,str)) {
int i;
// cout<<str;
size_t len = str.length();
const char *cstr = str.c_str();
for(i=0; (cstr[i]!='/' && cstr[i+1] !='/' && i < len); i++)
//cout<<i;
for(; cstr[i]!='\n' && i < len;i++) {
// cout<<i;
cout<<cstr[i];
}
cout<<endl;
}
return 0;
}
int main() {
while(getline(cin,str)) {
int i, len = str.size();
//always make sure that you are not accessing
//contents after your string has ended
for(i=0; i < (len - 1) && !(str[i] == '/' && str[i+1] == '/'); i++);
//note that i here might be the last alphabet
//if there's no comment
if(i < len && str[i] != '/')
i++;
//checking if str[i] != '\n' is not a good idea
//as c++ stl strings are not temrinated by '\n'
if(i < len) {
for(; i < len; i++)
cout << str[i];
cout << endl;
}
}
return 0;
}
Also note that both of the following codes won't terminate at the 4th character, c++ stl strings are not terminated by these characters.
string str = "hahahaha";
str[4] = '\n';
cout << str;
str[4] = '\0';
cout << str;
This is much easier to write and probably much faster than the other solutions to date.
#include <iostream>
int main()
{
std::string str;
while (std::getline(std::cin, str))
{
size_t loc = str.find("//");
if (loc != str.npos)
{
std::cout << str.substr(loc + 2)<< std::endl;
}
}
return 0;
}
It is also wrong.
Here is a nice, clean, and simple state machine version. Also pretty close to worst-case for speed. Thing is it's closest to being right, even though it is also wrong.
#include <iostream>
enum states
{
seeking1,
seeking2,
comment
};
int main()
{
std::string str;
while (std::getline(std::cin, str))
{
states state = seeking1;
for (char ch:str)
{
switch (state)
{
case seeking1:
if (ch == '/')
{
state = seeking2;
}
break;
case seeking2:
if (ch == '/')
{
state = comment;
}
else
{
state = seeking1;
}
break;
case comment:
std::cout << ch;
break;
}
}
if (state == comment)
{
std::cout << std::endl;
}
}
return 0;
}
Why are these approaches all wrong? Consider the line
cout << "Hi there! I am \\Not A Comment!" << endl;`
You can't just look at the \\, you also need the context. This is why the state machine above is the better option. It can be modified to handle, at the very least, states for handling strings and block comments.
I dont understand how to compare between string in c++??
string s1="abc";
string s[]={"abc","vsj"};
int length=sizeof(s)/sizeof(s[0]);//length of s
for(int i=0;i<length;i++)
{
if(s[i].compare(s1))
{
cout<<"One of the string equal to s1";
}
}
Is it possible??
Thanks..
std::string overloads operator==. You can compare 2 string using operato==. Also you can use std::vector instead of array. Using c++11:
#include <iostream>
#include <string>
#include <vector>
using namespace std;
int main() {
string s1="abc";
vector<string> ss = { "abc", "vsj" };
for (auto &s: ss) {
if (s == s1) {
cout<<"One of the string equal to s1";
}
}
return 0;
}
Using c++98:
#include <iostream>
#include <string>
#include <vector>
using namespace std;
int main() {
string s1="abc";
vector<string> ss;
ss.push_back("abc");
ss.push_back("vsj");
for (size_t i = 0; i < ss.size(); ++i) {
if (ss.at(i) == s1) {
cout<<"One of the string equal to s1";
}
}
return 0;
}
compare return the same values as strcmp:
<0 - the first character that does not match has a lower value in ptr1 than in ptr2
0 - the contents of both strings are equal
>0 - the first character that does not match has a greater value in ptr1 than in ptr2