Убрать и удвоить

Как убрать из строки определенные символы, например, все пробелы и знаки препинания? Есть очень простой способ. Заведем два указателя: один (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;

}


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: