0

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

user1939168
  • 547
  • 5
  • 20

5 Answers5

2

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)

Bjorn
  • 457
  • 1
  • 7
  • 22
  • Pls see my edit!. I donot have regex he4ader with my compiler – user1939168 Jul 01 '13 at 13:56
  • take a look at the following boost library: http://www.boost.org/doc/libs/1_53_0/libs/regex/doc/html/boost_regex/ref/regex_replace.html – Bjorn Jul 01 '13 at 14:00
  • 1
    @user1939168 You may not have `std::regex`, but you might be able to use `boost::regex` (although it is a mighty pain to install). Alternatively, since you are using Sun CC, you're probably on a Unix platform; Unix defined a `` header, and while it's much less comfortable than Boost or the standard, it's still a start. – James Kanze Jul 01 '13 at 14:00
1

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.

Community
  • 1
  • 1
Bernhard Barker
  • 54,589
  • 14
  • 104
  • 138
1

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

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;

}
Rajesh M
  • 634
  • 11
  • 31
0

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))
Sceptical Jule
  • 889
  • 1
  • 8
  • 26