user1939168
user1939168

Reputation: 557

Replace space in string

I am not quite good in C++ STL's. I have string like :

   x  ,y z  ,  a ,b, some text ,

I want all the spaces in this to be removed except the space which is in between two words So i want the output to be :

x,y z,a,b,some text,

I can easily do this in perl with :

perl -pe 's/\s*,\s*/,/g;s/^\s*//g'

But i need it in C++.

What i can do till now is :

line.erase(remove_if(line.begin(), line.end(), isspace), line.end()); 

But this removes all the splaces in the line.

I am using a compiler:

> CC -V
CC: Sun C++ 5.9 SunOS_i386 Patch 124864-01 2007/07/25

which does not have regex header

Upvotes: 0

Views: 1498

Answers (5)

Rajesh M
Rajesh M

Reputation: 634

I have done it using stack.What you do is initialize a stack and you have spaces ignore and when you come across a character u push the characters until ',' appears, and after pushing you pop all the spaces until a character has occurred(see below program in else part i have done) afterwards you form a string from the elements in stack and reverse the string you will required answer.If any body got any thing wrong in this please let me know

#include<iostream>
#include<stack>
#include<algorithm>
using namespace std;
void remove(stack<char> &mystack,int &i,string s)
{

while(s[i]!=',')
{
    int v;

    mystack.push(s[i]);
    i++;
}
}
int main()
{
string s = "   x  ,y  z  ,  a ,b, some text , ";
string r,str;
stack<char> mystack;

int i=0;
while(i<s.length())
{

    if(s[i]==' ')
    {

    i++;

}
    else if(s[i]==',')
{
    mystack.push(s[i]);
    i++;
}
    else 
    {
        remove(mystack,i,s);

    char c=mystack.top();
    while(c==' ')
    {
        mystack.pop();
        c=mystack.top();

    }

}

}

    while(!mystack.empty())
    {
        char c=mystack.top();
        str=str+c;
        mystack.pop();


    }
    reverse(str.begin(),str.end());
    cout<<str;

}

Upvotes: 1

Aaron Kyle Killeen
Aaron Kyle Killeen

Reputation: 56

This was tricky, some things I figured out when going through this:

  1. If you're iterating through the string in some kind of loop on each cycle you need to either erase or increment your iterator. DO NOT do both, you will erase a value and then skip a value.
  2. Watch the iterators here, be sure not to attempt to access anything out of scope, in particular if you're checking if the values before and after are letters, you have to start one past the beginning and stop one before the end and then independently check the one at the beginning, the one at the end I think should be fine because of the off the end iterator.
  3. The logic might be a little confusing too, it's kind of like a double negative. The ones that are not surrounded by letters are not kept around.

I tried to avoid using c++ 11, highly recommend it though, so much nicer to type auto than string::iterator. It did produce the text exactly as you typed it and this seems fairly simple too.

#include <iostream>
#include <string>
#include <cctype>
using namespace std;

int main()
{
string mytext = "   x  ,y z  ,  a ,b, some text ,";
string::iterator it = (mytext.begin() + 1);
while(it != (mytext.end() - 1))
{
if(*it == ' ' && !(isalpha(*(it-1)) && isalpha(*(it+1))))
mytext.erase(it);
else
++it;
}
if(*(mytext.begin()) == ' ')
mytext.erase(mytext.begin()); 

cout << "x,y z,a,b,some text," << endl;
cout << mytext << endl;
return 0;
}

Upvotes: 1

Sceptical Jule
Sceptical Jule

Reputation: 917

A C++ implementation without regex could look like this (based on the string example above):

for (size_t pos = 1; pos < line.size() - 1; pos = line.find (' ', pos+1))
    if (line[pos-1] == ',' || line[pos-1] == ' ' || line[pos+1] == ',' || line[pos+1] == ' ')
    {
        line.erase(pos, 1);
        --pos;
    }
if (line[0] == ' ')
    line.erase(0, 1);
if (line[line.size() - 1] == ' ')
    line.erase(line[line.size() - 1], 1);  //line.pop_back() for C++11

You can also use std::isalpha() from in the second line:

std::locale loc;
//...
    if (!std::isalpha(line[pos-1], loc) && !std::isalpha(line[pos+1], loc))

Upvotes: 0

Bernhard Barker
Bernhard Barker

Reputation: 55589

If Boost is an option, you should be able to use your regex like this.

Otherwise you can simply run a for-loop through the string and skip spaces where the next or previous character is a comma or space:

#include <iostream>
#include <string>

using namespace std;

bool isCommaOrSpace(char c)
{
   return c == ' ' || c == ',';
}

int main()
{
   string source = "   x  ,y  z  ,  a ,b, some text , ";
   string result = "";
   char last = ' ';
   for (unsigned int i=0; i<source.length(); i++)
   {
      if (source[i] != ' ' ||
          (!isCommaOrSpace(last) &&
           i < source.length()-1 && !isCommaOrSpace(source[i+1])))
      {
         result += source[i];
         last = source[i];
      }
   }

  cout << result << endl;

  int len;
  cin >> len;
  return 0;   
}

Test.

Upvotes: 1

Bjorn
Bjorn

Reputation: 465

You can use the library regex in your code and use the regex you use in perl

Information about regex library

edit:

if you don't have c++11 than you can look at boost, have a look to the following link: Boost library (regex section)

Upvotes: 2

Related Questions