Назад | Начало урока | Вперед
Содержание

Глава 3

Пример обработки строк
Если вы внимательно рассматривали примеры программ в книге, то наверняка обратили внимание на специальные маркеры в комментариях. Они используются программой Python для извлечения программного кода из файлов и построения make-файлов.

Например последовательность //: в начале строки обозначает первую строку программы. За этим символом следует инф с именем файла, его местонахождением и флагом, который указывает, что программу необходимо только откомпилировать (без построения исполняемого файла).

Так первая строка предыдущей программы содержит строку IWCompare.cpp , означающую, что файл IWCompare.cpp извлекается из текстового файла в каталог C03.

Последняя строка фрагмента помечается последовательностью ///:~. Если в первой строке сразу же после двоеточия следует восклицательный знак, первая и последняя строки кода не выводятся в файл (для файлов, содержащих только данные).

Возможности программы Python не ограничиваются простым извлечением кода. Если за именем файла следует маркер {Q}, то запись в make-файле настраивается на компиляцию исхожного текста программы без его компоновки в исполняемый файл (в частности так строится текстовая система в главе 2). Чтобы скомпоновать такой файл с другим исходным файлом, включите в исходный код исполняемой программы директиву {L}:

//{L} ../TestSuite/Test

В этом разделе будет представлена утилита, которая извлекает из текста книги весь код (вы можете самостоятельно просмотреть и откомпилировать примеры программ). Сохраните документ в текстовом формате (допустим в файле TICV2.txt) и введите в командной строке следующую команду:

C:> extractCode TICV2.txt /TheCode

Команда читает текстовый файл TICV2.txt и сохраняет весь программный код в подкаталогах каталога /TheCode. Дерево каталогов будет выглядеть так:

TheCode/
C0B/
C01/
C02/
C03/
C04/
C05/
C06/
C07/
C08/
C09/
C10/
C11/
TestSuite/

Файлы с исходными текстами примеров каждой главы находятся в соответствующем каталоге.

А вот и сама программа:

Вверх

Извлечение программного кода из текста


//: C03:ExtractCode.cpp
// Извлечение программного кода из текста
#include <cassert>
#include <cstddef>
#include <cstdio>
#include <cstdlib>
#include <fstream>
#include <iostream>
#include <string>
using namespace std;
// Унаследованный нестандартный заголовочных файл С для mkdir()
#if defined (__GNUC__) || defined(__MSWERKS__)
#include <sys/stat.h>
#elif defined(__BORLANDC__) || defined(_MSC_VER)
|| defined(__DMC__)
#include <direct.h>
#else
#error Compiler not supported
#endif

// Чтобы проверить, существует ли каталог, мы пытаемся
// открыть в нем новый файл для вывода. bool exists(string fname) {

size_t len = fname.length();
if(fname[len-1] != '/' && fname[len-1] != '\\')
fname.append("/");
fname.append("000.tmp");
ofstream outf(fname.c_str());
bool existFlag = outf; if (outf) {
outf.close();
remove(fname.c_str());
}
return existFlag;
}

int main(int argc, char* argv[]) {

// Проверяем, указано ли имя входного файла if(argc == 1) {
cerr << "usage: extractCode file [dir]\n";
exit(EXIT_FAILURE);
}
// Проверяем,существует ли входной файл
ifstream inf(argv[1]); if(!inf) {
cerr << "error opening file: " << argv[1] << endl;
exit(EXIT_FAILURE);
}
// Проверяем наличие необязательного входного каталога
string root("./"); // По умолчанию используется текущий каталог if(argc == 3) {
// Проверяем, существует ли входной каталог
root = argv[2]; if(!exists(root)) {
cerr << "no such directory: " << root << endl;
exit(EXIT_FAILURE);
}
size_t rootLen = root.length();
if(root[rootLen-1] != '/' && root[rootLen-1] != '\\')
root.append("/");
}
// Построчное чтение входного файла
// с проверкой маркеров начала и конца программных блоков
string line;
bool inCode = false;
bool printDelims = true;
ofstream outf; while (getline(inf, line)) {
size_t findDelim = line.find("//" "/:~"); if(findDelim != string::npos) {
// Вывод последней строки и закрытие файла if (!inCode) {
cerr << "Lines out of order\n";
exit(EXIT_FAILURE);
}
assert(outf);
if (printDelims)
outf << line << endl;
outf.close();
inCode = false;
printDelims = true;
} else {
findDelim = line.find("//" ":"); if(findDelim == 0) {
// Проверка директивы '!' if(line[3] == '!') {
printDelims = false;
++findDelim; // Чтобы пропустить '!' при следующем поиске
}
// Извлечение имени подкаталога (если оно есть)
size_t startOfSubdir =
line.find_first_not_of(" \t", findDelim+3);
findDelim = line.find(':', startOfSubdir); if (findDelim == string::npos) {
cerr << "missing filename information\n" << endl;
exit(EXIT_FAILURE);
}
string subdir;
if(findDelim > startOfSubdir)
subdir = line.substr(startOfSubdir,
findDelim - startOfSubdir);
// Извлечение обязательного имени файла
size_t startOfFile = findDelim + 1;
size_t endOfFile =
line.find_first_of(" \t", startOfFile); if(endOfFile == startOfFile) {
cerr << "missing filename\n";
exit(EXIT_FAILURE);
}
// Все компоненты присутствуют: построение имени в fullPath
string fullPath(root);
if(subdir.length() > 0)
fullPath.append(subdir).append("/");
assert(fullPath[fullPath.length()-1] == '/');
if (!exists(fullPath))
#ifdef __GNUC__
mkdir(fullPath.c_str(), 0); // Создание подкаталога
#else
mkdir(fullPath.c_str()); // Создание подкаталога
#endif
fullPath.append(line.substr(startOfFile,
endOfFile - startOfFile));
outf.open(fullPath.c_str()); if(!outf) {
cerr << "error opening " << fullPath
<< " for output\n";
exit(EXIT_FAILURE);
}
inCode = true;
cout << "Processing " << fullPath << endl;
if(printDelims)
outf << line << endl;
} else if(inCode) {
assert(outf); outf << line << endl; // Вывод строки программы
}
}
}
exit(EXIT_SUCCESS);
} ///:~


Назад | Начало урока | Вверх | Вперед
Содержание

Hosted by uCoz