Как убрать из строки определенные символы, например, все пробелы и знаки препинания? Есть очень простой способ. Заведем два указателя: один (p) на ту часть строки, которую мы просматриваем, другой (p2) — на ту часть, в которую мы будем копировать символы, не являющиеся пробелами или знаками препинания. Если нам встретился знак препинания, пропускаем его, увеличивая только первый указатель. Таким образом, мы «собираем» все символы к началу строки (см. рисунок ниже).
char s[256], *p = s, *p2 = s;
gets(s);
while(*p) // Пока в строке есть символы
{ if(!ispunct(*p) &&!isspace(*p))
*(p2++) = *p; // Если не знак препинания, копируем
p++; // Переходим к следующему символу
}
*p2 = '\0';
puts(s);
Кстати, в Visual C++ функции ispunct, isspace довольно медленные, поэтому вместо них лучше написать условие типа
if((*p '/' && *p '@' && *p '`' && *p '~') // примерно на 10% быстрее, чем!ispunct(p) &&!isspace(*p)
Как убрать из строки все вхождения подстроки, например, убрать все переносы строк? Точно также, как и в случае с удалением символа, будем копировать нужные нам части строки в её начало. Можно искать подстроку с помощью strstr() или применить макрос toShort:
Пример с использованием статической и динамической памяти, перегрузки, ввода-вывода в символьных множествах.
//Статическая память
//Set.h
#pragma once
#include <iostream>
using namespace std;
class Set
{
static const int max_power = 100; //максимальная мощность
char set [max_power]; //массив символов
int power; //мощность
public:
Set (): power(0) {}; //• пустой конструктор для инициализации
экземпляров и массивов экземпляров класса по умолчанию;
Set (const Set& s); //конструктор копирования
Set (int p); //• создание экземпляров класса с инициализацией мощностью
множества (начальное множество - символы, начиная с символа пробел);
Set (char* str);//• создание экземпляров класса с инициализацией
значениями элементов множества как строки символов;
~Set () {}; //деструктор
Set& operator = (const Set& s); //оператор присваивания
Set& operator += (const char e);//• добавление нового элемента в
множество (с помощью перегруженного оператора +=);
bool In (char e) const;//• определение, имеется ли некоторый заданный
элемент в множестве.
bool Encode (char* instr, char* outstr, int n); //кодирование строки
bool Decode (char* instr, char* outstr, int n); //декодирование строки
friend Set operator - (const Set &p1, const Set &p2); //• вычисление
разности двух множеств (с помощью перегруженного оператора вычитания -;
результирующее множество должно состоять из элементов первого множества без
тех, которые есть во втором множестве);
friend Set operator * (const Set &p1, const Set &p2); //• вычисление
пересечения двух множеств (с помощью перегруженного оператора умножения *;
результирующее множество должно состоять из элементов, имеющихся и в множестве
1, и в множестве 2);
friend Set operator + (const Set &p1, const Set &p2); //• объединение
двух множеств (с помощью перегруженного оператора сложения +; результирующее
множество должно содержать элементы множества 1 и отличающиеся элементы
множества 2);
friend istream & operator >> (istream & in, Set & p);
// ввод экземпляров класса из входного потока
friend ostream & operator << (ostream & out, const Set & p);
// вывод в выходной поток
private:
int Find (char c);
};
//Set.cpp
#include "stdafx.h"
#include "Set.h"
Set::Set (const Set& s)
{
power = s.power; //копируем мощность
memcpy (set, s.set, sizeof(char)*power); //копируем данные
}
Set::Set (int p)
{
if (p>max_power) { //если переданная мощность больше максимальной
power = 0; //инициализируем по умолчанию
return;
}
power = p; //сохраняем мощность
char b [] = {65, 48, 97};
char e [] = {90, 57, 255};
int j = 0;
for (int i = 0; i<p; i++) { //заполняем символами
set[i] = b[j]++;
if (b[j]>e[j]) j++;
}
}
Set::Set (char* str)
{
power = 0; //обнуляем мощность
int len = strlen (str); //получаем длину строки
if (len > max_power) return; //если она больше максимальной -
выходим
for (int i = 0; i<len; i++) //Заполняем символами из строки
*this+=str[i];
}
Set& Set::operator = (const Set& s)
{ //аналогично конструктору копирования
power = s.power;
memcpy (set, s.set, sizeof(char)*power);
return *this;
}
Set& Set::operator += (const char e)
{
if (power+1>max_power || In(e)) return *this; //если максимальная
мощность достигнута или такой элемент уже есть - выходим
set[power] = e; //Добавляем в конец
power++; //увеличиваем мощность
}
bool Set::In (char e) const
{
for (int i = 0; i<power; i++) //ищем символ в массиве
if (set[i] == e) return true; //нашли - возвращаем 1
return false; //не нашли - 0
}
bool Set::Encode (char* instr, char* outstr, int n)
{
int y, l = strlen(instr); //сохраняем длину
for (int i=0; i<l; i++) { //идём по строке
y = Find (instr[i]); //ищем символ в алфавите
if (y<0) return false; //если нет - возвращаем ошибку
if ((y+n)>=power) y = y + n - power; //вычисляем позицию
нового символа
else y+=n;
outstr[i] = set[y]; //пишем закодированный символ
}
outstr[l] = \'\0\'; //обозначаем конец строки
return true;
}
bool Set::Decode (char* instr, char* outstr, int n)
{//всё то же, что в кодировании, только индекс вычисляется наоборот, вычитанием
int y, l = strlen(instr);
for (int i=0; i<l; i++) {
y = Find (instr[i]);
if (y<0) return false;
if ((y-n)<0) y = power + y - n;
else y-=n;
outstr[i] = set[y];
}
outstr[l] = \'\0\';
return true;
}
int Set::Find (char c)
{//вспомогательная фукнция: вычисляет индекс символа в алфавите
for (int i = 0; i<power; i++) //ищем символ в массиве
if (set[i] == c) return i; //нашли - возвращаем i
return -1; //не нашли - -1
}
Set operator - (const Set &p1, const Set &p2)
{
Set tmp; //буфер
for (int i = 0; i<p1.power; i++) //идём по символам первого
множества
if (!p2.In(p1.set[i])) tmp+=p1.set[i]; //если символ первого не
содержится во втором, добавляем к результату
return tmp; //возвращаем буфер
}
Set operator * (const Set &p1, const Set &p2)
{
Set tmp;
for (int i = 0; i<p1.power; i++) //если символ первого содержится во
втором, добавляем к результату
if (p2.In(p1.set[i])) tmp+=p1.set[i];
return tmp;
}
Set operator + (const Set &p1, const Set &p2)
{
Set tmp;
for (int i = 0; i<p1.power; i++) //просто добавляем к результату все
символы первого и второго множеств
tmp+=p1.set[i]; //повторные не добавятся из-за реализации
оператора +=
for (int i = 0; i<p2.power; i++)
tmp+=p2.set[i];
return tmp;
}
istream & operator >> (istream & in, Set & p)
{
cout << "Enter power: ";
in >> p.power;
cout << "Enter chars: ";
for (int i=0; i<p.power; i++)
in >> p.set[i];
return in;
}
ostream & operator << (ostream & out, const Set & p)
{
out << "{ ";
for (int i = 0; i<p.power-1; i++)
out << p.set[i] << ", ";
out << p.set[p.power-1] << " }";
return out;
}
// Динамическая память
//Set.h
#pragma once
#include <iostream>
using namespace std;
class Set
{
char* set; //массив символов
int power; //мощность
public:
Set (): power(0), set(NULL) {}; //• пустой конструктор для
инициализации экземпляров и массивов экземпляров класса по умолчанию;
Set (const Set& s); //конструктор копирования
Set (int p); //• создание экземпляров класса с инициализацией мощностью
множества (начальное множество - символы, начиная с символа пробел);
Set (const char* str);//• создание экземпляров класса с инициализацией
значениями элементов множества как строки символов;
~Set (); //деструктор
Set& operator = (const Set& s); //оператор присваивания
Set& operator += (const char e);//• добавление нового элемента в
множество (с помощью перегруженного оператора +=);
bool In (char e) const;//• определение, имеется ли некоторый заданный
элемент в множестве.
bool Encode (char* instr, char* outstr, int n); //кодирование строки
bool Decode (char* instr, char* outstr, int n); //декодирование строки
friend Set operator - (const Set &p1, const Set &p2); //• вычисление
разности двух множеств (с помощью перегруженного оператора вычитания -;
результирующее множество должно состоять из элементов первого множества без
тех, которые есть во втором множестве);
friend Set operator * (const Set &p1, const Set &p2); //• вычисление
пересечения двух множеств (с помощью перегруженного оператора умножения *;
результирующее множество должно состоять из элементов, имеющихся и в множестве
1, и в множестве 2);
friend Set operator + (const Set &p1, const Set &p2); //• объединение
двух множеств (с помощью перегруженного оператора сложения +; результирующее
множество должно содержать элементы множества 1 и отличающиеся элементы
множества 2);
friend istream & operator >> (istream & in, Set & p);
// ввод экземпляров класса из входного потока
friend ostream & operator << (ostream & out, const Set & p);
// вывод в выходной поток
private:
void IncSize (); //увеличение размера множества на 1
int Find (char c);
};
//set.cpp
#include "StdAfx.h"
#include "Set.h"
Set::~Set ()
{
if (set!=NULL) delete [] set; //очистка памяти
}
Set::Set (const Set& s)
{
power = s.power; //копируем мощность
set = new char [power]; //выделение памяти
memcpy (set, s.set, sizeof(char)*power); //копируем данные
}
Set::Set (int p)
{
power = p; //сохраняем мощность
set = new char [power];
char b [] = {65, 48, 97};
char e [] = {90, 57, 255};
int j = 0;
for (int i = 0; i<p; i++) { //заполняем символами
set[i] = b[j]++;
if (b[j]>e[j]) j++;
}
}
Set::Set (const char* str)
{
power = 0;
set = NULL;
int len = strlen (str); //получаем длину строки
//set = new char [len];
for (int i = 0; i<len; i++) //Заполняем символами из строки
*this+=str[i];
}
Set& Set::operator = (const Set& s)
{ //аналогично конструктору копирования
power = s.power;
if (set!=NULL) delete [] set;
set = new char [power];
memcpy (set, s.set, sizeof(char)*power);
return *this;
}
void Set::IncSize ()
{
power++; //увеличиваем мощность
if (set==NULL) { //если множество пустое, просто выделяем память
set = new char [power];
return; //и выходим
}
char* s1 = set; //сохраняем старый адрес
set = new char [power]; //выделяем память под новый размер
memcpy (set, s1, sizeof(char)*(power-1)); //копируем элементы
delete [] s1; //очищаем старую память
}
Set& Set::operator += (const char e)
{
if (In(e)) return *this; //если такой элемент уже есть - выходим
IncSize();
set[power-1] = e; //Добавляем в конец
}
bool Set::In (char e) const
{
for (int i = 0; i<power; i++) //ищем символ в массиве
if (set[i] == e) return true; //нашли - возвращаем 1
return false; //не нашли - 0
}
bool Set::Encode (char* instr, char* outstr, int n)
{
int y, l = strlen(instr); //сохраняем длину
for (int i=0; i<l; i++) { //идём по строке
y = Find (instr[i]); //ищем символ в алфавите
if (y<0) return false; //если нет - возвращаем ошибку
if ((y+n)>=power) y = y + n - power; //вычисляем позицию
нового символа
else y+=n;
outstr[i] = set[y]; //пишем закодированный символ
}
outstr[l] = \'\0\'; //обозначаем конец строки
return true;
}
bool Set::Decode (char* instr, char* outstr, int n)
{//всё то же, что в кодировании, только индекс вычисляется наоборот, вычитанием
int y, l = strlen(instr);
for (int i=0; i<l; i++) {
y = Find (instr[i]);
if (y<0) return false;
if ((y-n)<0) y = power + y - n;
else y-=n;
outstr[i] = set[y];
}
outstr[l] = \'\0\';
return true;
}
int Set::Find (char c)
{//вспомогательная фукнция: вычисляет индекс символа в алфавите
for (int i = 0; i<power; i++) //ищем символ в массиве
if (set[i] == c) return i; //нашли - возвращаем i
return -1; //не нашли - -1
}
Set operator - (const Set &p1, const Set &p2)
{
Set tmp; //буфер
for (int i = 0; i<p1.power; i++) //идём по символам первого
множества
if (!p2.In(p1.set[i])) tmp+=p1.set[i]; //если символ первого не
содержится во втором, добавляем к результату
return tmp; //возвращаем буфер
}
Set operator * (const Set &p1, const Set &p2)
{
Set tmp;
for (int i = 0; i<p1.power; i++) //если символ первого содержится во
втором, добавляем к результату
if (p2.In(p1.set[i])) tmp+=p1.set[i];
return tmp;
}
Set operator + (const Set &p1, const Set &p2)
{
Set tmp;
for (int i = 0; i<p1.power; i++) //просто добавляем к результату все
символы первого и второго множеств
tmp+=p1.set[i]; //повторные не добавятся из-за реализации
оператора +=
for (int i = 0; i<p2.power; i++)
tmp+=p2.set[i];
return tmp;
}
istream & operator >> (istream & in, Set & p)
{
cout << "Enter power: ";
in >> p.power;
if (p.set!=NULL) delete [] p.set;
p.set = new char [p.power];
cout << "Enter chars: ";
for (int i=0; i<p.power; i++)
in >> p.set[i];
return in;
}
ostream & operator << (ostream & out, const Set & p)
{
out << "{ ";
for (int i = 0; i<p.power-1; i++)
out << p.set[i] << ", ";
out << p.set[p.power-1] << " }";
return out;
}