user3760100
user3760100

Reputation: 685

Error when trying to reverse string except for special characters

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?

Upvotes: 1

Views: 180

Answers (2)

Ami Tavory
Ami Tavory

Reputation: 76346

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;
}

Upvotes: 3

Vlad from Moscow
Vlad from Moscow

Reputation: 311068

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!$

Upvotes: 2

Related Questions