Error when trying to reverse string except for special characters - c++

I need to reverse only the parts of the string that are alphabetic while leaving the special characters in the string untouched. For example,
Input: str = "Ab,c,de!$"
Output: str = "ed,c,bA!$"
I have written the following C++ code to do the same:
#include<stdio.h>
#include<iostream>
#include<string>
#include<math.h>
#include<stdlib.h>
#include<ctype.h>
using namespace std;
int main() {
char s[100],t[100];
cin>>s;
int len;
for ( len = 0; ; len++ ) {
if( s[len] =='\0') {
break;
}
}
//cout<<len<<endl;
t[len] = '\0';
for ( int i = 0; i < len; i++ ) {
if ( isalpha(s[i])) {
t[len-i-1] = s[i];
// cout<<t[len-i-1]<<endl;
}
else {
t[i] = s[i];
//cout<<t[i]<<endl;
}
}
//cout<<s<<endl;
cout<<t;
return 0;
}
For the above mentioned sample input, I get SOH as the output instead. What is the mistake I am making?

It occurred to me that it would be natural to write this using boost::iterator::filter_iterator and std::reverse:
#include <string>
#include <algorithm>
#include <iostream>
#include <boost/iterator/filter_iterator.hpp>
using namespace std;
int main()
{
auto is_regular = [](char c){return c != ',';};
string s{"hello, cruel world"};
std::reverse(
boost::make_filter_iterator(is_regular, s.begin(), s.end()),
boost::make_filter_iterator(is_regular, s.end(), s.end()));
cout << s << endl;
}
This outputs:
dlrow, leurc olleh
Note that this only treats commas as special, but you get the idea.
Following is a solution that is more along the lines of the the code in your question. I think the problem is that, to do this correctly, you need to have two indices - one running from the left and one from the right - and run until they cross each other. Otherwise you can get all sorts of strange things like things being crossed twice.
#include<stdio.h>
#include<iostream>
#include<string>
#include<math.h>
#include<stdlib.h>
#include<ctype.h>
#include<cstring>
using namespace std;
int main()
{
char s[101]="hello, cruel world", t[100];
auto len = strlen(s);
t[len--] = '\0';
//cout<<len<<endl;
int i = 0;
while(i <= len)
if (!isalpha(s[i]))
{
t[i] = s[i];
++i;
continue;
}
else if (!isalpha(s[len]))
{
t[len] = s[len];
--len;
continue;
}
else
{
t[len] = s[i];
t[i] = s[len];
++i;
--len;
}
cout<<t<< endl;
return 0;
}

It is better and more safe to use standard class std::string instead of a character array.
The program can look the following way
#include <iostream>
#include <string>
#include <cctype>
int main()
{
std::string s;
std::getline( std::cin, s );
if ( !s.empty() )
{
for ( std::string::size_type first = 0, last = s.size(); first < --last; ++first )
{
while ( first != last && !std::isalpha( ( unsigned char )s[first] ) ) ++first;
while ( first != last && !std::isalpha( ( unsigned char )s[last] ) ) --last;
if ( first != last ) std::swap( s[first], s[last] );
}
std::cout << s << std::endl;
}
}
If to enter string
Ab,c,de!$
then the output will look like
Ab,c,de!$
ed,c,bA!$

Related

string repetition replaced by hyphen c++

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.

How to count characters that appear twice consecutively

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 getting a segmentation fault in this code and can't understand why?

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.

Function to parse string with tokens

I know how to program in C# and VB but not have idea about how to use C++ and have to program a little exe to a barcode scanner that use C++ :(
In this moment I try to parse a scanned barcode that have multiple data sepparated with a "/", I find that exist a strtok function, tested it "manually" and worked ok but I not implemented yet a working function to call it correctly, what I have now:
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
int elemStr(char *str, char sep)
{
int cantElem;
unsigned ich;
cantElem = 0;
if (strlen(str) > 0) //at least 1 elem
cantElem++;
for (ich = 0; ich < strlen(str); ich++)
{
if (str[ich] == sep)
cantElem++;
}
return cantElem;
}
char* getElemStr(char *str, char sep[], int elem)
{
char *tempStr = NULL;
char *tok;
int currElem = 1;
// 1st data
strcpy( tempStr, str);
tok = strtok( tempStr, sep);
while( currElem != elem )
{
// Get next tokens:
tok = strtok( NULL, sep );
currElem++;
}
return tok;
}
void main( void )
{
char barcode[] = "710015733801Z/1/35";
char sep[] = "/";
char sep1 = sep[0];
char barcd[20];
char piezaChar[4];
int pieza;
char mtsChar[4];
int cantElem;
cantElem = elemStr(barcode, sep1 );
if (cantElem >= 1)
{
strcpy(barcd, getElemStr(barcode,sep,1) ); //pasa a str resultado;
printf("Cod: %s\n", barcd ); //STACK OVERFLOW HERE!
}
}
if I use strtok witout a function "getElemStr" it work ok but I try to use it on other places too.
Can I use strtok like this? You have a working example?
pd: I not have idea about pointers (sorry), good doc to learn about that?
Since you specifically asked about C++, I'm going to ignore your very c-style code and show you how to do this in C++:
#include <boost/algorithm/string.hpp>
#include <iostream>
#include <string>
#include <vector>
int main()
{
std::string barcode = "710015733801Z/1/35";
std::string sep = "/";
std::vector<std::string> v;
boost::split(v, barcode, boost::is_any_of(sep));
for(size_t i=0; i<v.size(); ++i)
std::cout << v[i] << '\n';
}
strtok destroys your original string. So i don't think it can be used with a char* that points to a static string. Static strings get copied to a read only portion of the executable.
Here is a C++ solution that doesn't use boost.
#include <string>
#include <sstream>
#include <iostream>
int main()
{
std::string barcode = "710015733801Z/1/35";
std::stringstream ss(barcode);
std::string elem;
while(std::getline(ss, elem, '/'))
{
//do something else meaningful with elem
std::cout << elem << std::endl;
}
return 0;
}
Output:
710015733801Z
1
35

Count character occurrences in a string in C++

How can I count the number of "_" in a string like "bla_bla_blabla_bla"?
#include <algorithm>
std::string s = "a_b_c";
std::string::difference_type n = std::count(s.begin(), s.end(), '_');
Pseudocode:
count = 0
For each character c in string s
Check if c equals '_'
If yes, increase count
EDIT: C++ example code:
int count_underscores(string s) {
int count = 0;
for (int i = 0; i < s.size(); i++)
if (s[i] == '_') count++;
return count;
}
Note that this is code to use together with std::string, if you're using char*, replace s.size() with strlen(s).
Also note: I can understand you want something "as small as possible", but I'd suggest you to use this solution instead. As you see you can use a function to encapsulate the code for you so you won't have to write out the for loop everytime, but can just use count_underscores("my_string_") in the rest of your code. Using advanced C++ algorithms is certainly possible here, but I think it's overkill.
Old-fashioned solution with appropriately named variables. This gives the code some spirit.
#include <cstdio>
int _(char*__){int ___=0;while(*__)___='_'==*__++?___+1:___;return ___;}int main(){char*__="_la_blba_bla__bla___";printf("The string \"%s\" contains %d _ characters\n",__,_(__));}
Edit: about 8 years later, looking at this answer I'm ashamed I did this (even though I justified it to myself as a snarky poke at a low-effort question). This is toxic and not OK. I'm not removing the post; I'm adding this apology to help shifting the atmosphere on StackOverflow. So OP: I apologize and I hope you got your homework right despite my trolling and that answers like mine did not discourage you from participating on the site.
Using the lambda function to check the character is "_" then the only count will be incremented else not a valid character
std::string s = "a_b_c";
size_t count = std::count_if( s.begin(), s.end(), []( char c ){return c =='_';});
std::cout << "The count of numbers: " << count << std::endl;
#include <boost/range/algorithm/count.hpp>
std::string str = "a_b_c";
int cnt = boost::count(str, '_');
You name it... Lambda version... :)
using namespace boost::lambda;
std::string s = "a_b_c";
std::cout << std::count_if (s.begin(), s.end(), _1 == '_') << std::endl;
You need several includes... I leave you that as an exercise...
Count character occurrences in a string is easy:
#include <bits/stdc++.h>
using namespace std;
int main()
{
string s="Sakib Hossain";
int cou=count(s.begin(),s.end(),'a');
cout<<cou;
}
There are several methods of std::string for searching, but find is probably what you're looking for. If you mean a C-style string, then the equivalent is strchr. However, in either case, you can also use a for loop and check each character—the loop is essentially what these two wrap up.
Once you know how to find the next character given a starting position, you continually advance your search (i.e. use a loop), counting as you go.
I would have done it this way :
#include <iostream>
#include <string>
using namespace std;
int main()
{
int count = 0;
string s("Hello_world");
for (int i = 0; i < s.size(); i++)
{
if (s.at(i) == '_')
count++;
}
cout << endl << count;
cin.ignore();
return 0;
}
You can find out occurrence of '_' in source string by using string functions.
find() function takes 2 arguments , first - string whose occurrences we want to find out and second argument takes starting position.While loop is use to find out occurrence till the end of source string.
example:
string str2 = "_";
string strData = "bla_bla_blabla_bla_";
size_t pos = 0,pos2;
while ((pos = strData.find(str2, pos)) < strData.length())
{
printf("\n%d", pos);
pos += str2.length();
}
The range based for loop comes in handy
int countUnderScores(string str)
{
int count = 0;
for (char c: str)
if (c == '_') count++;
return count;
}
int main()
{
string str = "bla_bla_blabla_bla";
int count = countUnderScores(str);
cout << count << endl;
}
I would have done something like that :)
const char* str = "bla_bla_blabla_bla";
char* p = str;
unsigned int count = 0;
while (*p != '\0')
if (*p++ == '_')
count++;
Try
#include <iostream>
#include <string>
using namespace std;
int WordOccurrenceCount( std::string const & str, std::string const & word )
{
int count(0);
std::string::size_type word_pos( 0 );
while ( word_pos!=std::string::npos )
{
word_pos = str.find(word, word_pos );
if ( word_pos != std::string::npos )
{
++count;
// start next search after this word
word_pos += word.length();
}
}
return count;
}
int main()
{
string sting1="theeee peeeearl is in theeee riveeeer";
string word1="e";
cout<<word1<<" occurs "<<WordOccurrenceCount(sting1,word1)<<" times in ["<<sting1 <<"] \n\n";
return 0;
}
public static void main(String[] args) {
char[] array = "aabsbdcbdgratsbdbcfdgs".toCharArray();
char[][] countArr = new char[array.length][2];
int lastIndex = 0;
for (char c : array) {
int foundIndex = -1;
for (int i = 0; i < lastIndex; i++) {
if (countArr[i][0] == c) {
foundIndex = i;
break;
}
}
if (foundIndex >= 0) {
int a = countArr[foundIndex][1];
countArr[foundIndex][1] = (char) ++a;
} else {
countArr[lastIndex][0] = c;
countArr[lastIndex][1] = '1';
lastIndex++;
}
}
for (int i = 0; i < lastIndex; i++) {
System.out.println(countArr[i][0] + " " + countArr[i][1]);
}
}