Глава 3
Вверх
Если поиск в строке требуется выполнять от конца к началу (чтобы искать данные "от последнего вхождения к первому"), воспользуйтесь функцией rfind():
class RparseTest : public TestSuite::Test {
void parseForData() { // Перебор строки в обратном направлении:
// Пропустить найденный ограничитель
// Получение первого слова, не имеющего
void testData() { void run() {
int main() {
This is going to make sense now. !!!
Анализ:
Строковая функция rfind() перебирает строку в обратном направлении, ищет заданные лексемы и возвращает массив(!) индексов совпадающих символов (При отсутствии совпадений возвращает string::npos.)
Итак все по порядку:
Объявляем вектор strings.
Затем пишем две функции: parseForData() и testData(), которые будут вызваны в третьей функции - run().
В функции parseForData(), строковая функция rfind() перебирает строку в обратном направлении, ищет заданные лексемы. В данном случае она ищет символ ";". Найдя этот символ в первый раз, функция возвращает его позицию в строке, которую мы сохраняем в переменной current. Далее нас у есть две переменных - текущая позиция (current) и конечная позиция (last). Теперь используем эти две переменных в вызове функции substr():
Эта функция возвратит подстроку, которую мы положим в вектор при помощи его функции push_back():
Далее присвоим переменной last значение переменной current, и вновь вызовем функцию rfind передав ей два параметра - символ для поиска и начальную позицию поиска:
// Пропустить найденный ограничитель
Так в цикле мы разобьем всю строку на подстроки и сложим все подстроки в вектор. Каждую подстроку в свою ячейку вектора. Так работает функция parseForData().
Далее есть функция testData(), которая тестирует содержимое вектора strings. И далее в цикле при помощи оператора конкатенации и перебирая все элементы вектора, складывает их
в новую строку sentence. Затем тестирует содержание этой новой строки, действительно ли она содержит "This is going to make sense now.". Все верно! Программа работает!
Эккель использует свой стиль программирования. Он не выводит строки на консоль для проверки. А проверяет строку при помощи функции test_:
То есть сравнивает строку с эталонной. Удобный подход. Для того, чтобы он работал необходимо подключить заголовочный файл Test.h, как это сделано в программе. Поскольку у меня нет этого заголовочного файла, то я просто для проверки выводже строки на консоль, а строки типа test_(sentence == "This is going to make sense now."); ремирую.
Впрочем ничто не мешает мне написать самому подобный заголовочный файл и использовать эту технику в своих программах. Для разбиения строки на отдельные слова, в качестве разделителя мы можем использовать пробел. Кстати сделай такую программу разбиения строки на слова использовав в качестве прототипа данную программу!
Вверх
Следующая программа разбивает строку на слова и создает новую строку, в которой слова расположены в обратном порядке. В качестве разделителя используется пробел.
class RparseTest : public TestSuite::Test {
void parseForData() { // Перебор строки в обратном направлении:
// Пропустить найденный ограничитель
// Получение первого слова, не имеющего
void testData() { void run() {
int main() {
Программа не только разбила строку на слова, но и в новой строке расположила их в обратном порядке.
Назад |
Начало урока |
Вверх |
Вперед
Поиск в обратном направлении
//: C03:Rparse.h
#ifndef RPARSE_H
#define RPARSE_H
#include <cstddef>
#include <string>
#include <vector>
#include "../TestSuite/Test.h"
using std::size_t;
using std::string;
using std::vector;
vector<string> strings;
public:
string s("now.;sense;make;to;going;is;This");
// Последний элемент строки:
int last = s.size();
// Начало текущего слова:
size_t current = s.rfind(';');
while(current != string::npos){
// Переменная current инкрементируется перед копированием,
// чтобы предотвратить копирование ограничителя:
++current;
strings.push_back(s.substr(current, last - current));
// и установить last в конец следующего слова:
current -= 2;
last = current + 1;
// Поиск следующего ограничителя
current = s.rfind(';', current);
// префикса-ограничителя.
strings.push_back(s.substr(0, last));
test_(strings[0] == "This");
test_(strings[1] == "is");
test_(strings[2] == "going");
test_(strings[3] == "to");
test_(strings[4] == "make");
test_(strings[5] == "sense");
test_(strings[6] == "now.");
string sentence;
for(int i = 0; i < strings.size() - 1; i++)
sentence += strings[i] += " ";
// Вручную занести последнее слово, чтобы избежать
// сохранения лишнего пробела.
sentence += strings[strings.size() - 1];
test_(sentence == "This is going to make sense now.");
testData();
#endif // RPARSE_H ///:~
//: C03:Rparse.cpp
//{L} ../TestSuite/Test
#include "Rparse.h"
t.run();
return t.report();
Результат:
vector
s.substr(current, last - current)
strings.push_back(s.substr(current, last - current));
// и установить last в конец следующего слова:
current -= 2;
last = current + 1;
// Поиск следующего ограничителя
current = s.rfind(';', current);
}
test_(sentence == "This is going to make sense now.");
//: C03:Rparse.h
#ifndef RPARSE_H
#define RPARSE_H
#include <cstddef>
#include <string>
#include <vector>
#include <iostream>
using namespace std;
vector <string> strings;
public:
string s("In fact, his sleep was so short that he never had time to sober up ");
// Последний элемент строки:
int last = s.size();
// Начало текущего слова:
size_t current = s.rfind(' ');
while(current != string::npos){
// Переменная current инкрементируется перед копированием,
// чтобы предотвратить копирование ограничителя:
++current;
strings.push_back(s.substr(current, last - current));
// и установить last в конец следующего слова:
current -= 2;
last = current + 1;
// Поиск следующего ограничителя
current = s.rfind(' ', current);
// префикса-ограничителя.
strings.push_back(s.substr(0, last));
for(int i = 0; i < strings.size() - 1; i++)
sentence += strings[i] += " ";
// Вручную занести последнее слово, чтобы избежать
// сохранения лишнего пробела.
sentence += strings[strings.size() - 1];
testData();
#endif // RPARSE_H ///:~
//: C03:Rparse.cpp
#include "Rparse.h"
using namespace std;
t.run();
return 0;
Содержание