Карта сайта Kansoftware
НОВОСТИУСЛУГИРЕШЕНИЯКОНТАКТЫ
Разработка программного обеспечения

Tutorial

Boost , ,

Tutorial

2.2.5. Tab-Expanding Filters

Предположим, вы хотите написать фильтр, который заменяет каждый символ вкладки одним или несколькими символами пространства таким образом, чтобы документ отображался без изменений. Основной алгоритм выглядит следующим образом: Вы просматриваете символы по одному за раз, пересылая ихкак естьи отслеживая текущий номер столбца. Когда вы встречаете символ вкладки, вы заменяете его последовательностью пространственных символов, длина которых зависит от текущего количества столбцов. Когда вы сталкиваетесь с персонажем новой линии, вы перенаправляете его и сбрасываете счет столбца.

В следующих трех разделах я выражаю этот алгоритм как<stdio_filter>,InputFilterиOutputFilter.. Исходный код можно найти в заголовке<<libs/iostreams/example/tab_expanding_filter.hpp>>. Эти примеры были вдохновлены Джеймсом Канзе<ExpandTabsInserter.hh>см.[Канцзы].

tab_expanding_stdio_filter

Вы можете выразить расширяющий вкладку фильтр как<stdio_filter>следующим образом:

#include <cstdio>    // EOF
#include <iostream>  // cin, cout
#include <boost/iostreams/filter/stdio.hpp>
class tab_expanding_stdio_filter : public stdio_filter {
public:
    explicit tab_expanding_stdio_filter(int tab_size = 8)
        : tab_size_(tab_size), col_no_(0)
    {
        assert(tab_size > 0);
    }
private:
    void do_filter();
    void do_close();
    void put_char(int c);
    int  tab_size_;
    int  col_no_;
};
} } } // End namespace boost::iostreams:example

Функция помощника<put_char>идентична<line_wrapping_stdio_filter::put_char>. Он пишет символ<std::cout>и обновляет графу столбца:

    void put_char(int c)
    {
        std::cout.put(c);
        if (c == '\n') {
            col_no_ = 0;
        } else {
            ++col_no_;
        }
    }

<put_char>Вы можете использовать<do_filter>следующим образом:

    void do_filter()
    {
        int c;
        while ((c = std::cin.get()) != EOF) {
            if (c == '\t') {
                int spaces = tab_size_ - (col_no_ % tab_size_);
                for (; spaces > 0; --spaces)
                    put_char(' ');
            } else {
                put_char(c);
            }
        }
    }

<while>петля читает символ из<std::cin>и записывает его в<std::cout>, если только он не является символом вкладки, и в этом случае он пишет соответствующее количество символов пространства<std::cout>.

Как и<line_wrapping_stdio_filter>, функция<virtual><do_close>сбрасывает состояние фильтра:

    void do_close() { col_no_ = 0; }

tab_expanding_input_filter

Вы можете выразить расширяющий вкладку фильтр какInputFilterследующим образом:

#include <boost/iostreams/char_traits.hpp> // EOF, WOULD_BLOCK
#include <boost/iostreams/concepts.hpp>    // input_filter
#include <boost/iostreams/operations.hpp>  // get
namespace boost { namespace iostreams { namespace example {
class tab_expanding_input_filter : public input_filter {
public:
    explicit tab_expanding_input_filter(int tab_size = 8)
        : tab_size_(tab_size), col_no_(0), spaces_(0)
    { 
        assert(tab_size > 0); 
    }
    template<typename Source>
    int get(Source& src);
    template<typename Source>
    void close(Source&);
private:
    int get_char(int c);
    int   tab_size_;
    int   col_no_;
    int   spaces_;
};
} } } // End namespace boost::iostreams:example

Давайте сначала рассмотрим функцию помощника<get_char>:

    int get_char(int c)
    {
        if (c == '\n') {
            col_no_ = 0;
        } else {
            ++col_no_;
        }
        return c;
    }

Эта функция обновляет подсчет столбцов на основе заданного символа<c>и возвращает<c>. Используя<get_char>вы можете реализовать<get>следующим образом:

    template<typename Source>
    int get(Source& src)
    {
        if (spaces_ > 0) {
            --spaces_;
            return get_char(' ');
        }
        int c;
        if ((c = iostreams::get(src)) == EOF || c == WOULD_BLOCK)
            return c;
        if (c != '\t')
            return get_char(c);
        // Found a tab. Call this filter recursively.
        spaces_ = tab_size_ - (col_no_ % tab_size_);
        return this->get(src);
    }

Похожая ситуация наблюдается и в<line_wrapping_input_filter::get>. Поскольку<get>может вернуть только один символ за раз, всякий раз, когда символ вкладки должен быть заменен последовательностью пространственного символа, может быть возвращен только первый пространственный символ. Остальное должно быть возвращено последующими призывами<get>. Для хранения числа таких пространственных символов используется переменная<spaces_>.

Реализация начинается с проверки того, остаются ли какие-либо космические символы. Если это так, то он уменьшается<spaces_>и возвращает пространство. В противном случае персонаж читается<src>. Обычные символы, а также специальные значения<EOF>и<WOULD_BLOCK>возвращаютсякак есть. Когда встречается символ вкладки, записывается количество пространств, которое должно быть возвращено будущими вызовами получения, и возвращается пространственный символ.

Как обычно, функция<close>сбрасывает состояние фильтра:

    void close(Source&)
    {
        col_no_ = 0;
        spaces_ = 0;
    }

tab_expanding_output_filter

Вы можете выразить расширяющий вкладку фильтр какOutputFilterследующим образом:

#include <boost/iostreams/concepts.hpp>    // output_filter
#include <boost/iostreams/operations.hpp>  // put
namespace boost { namespace iostreams { namespace example {
class tab_expanding_output_filter : public output_filter {
public:
    explicit tab_expanding_output_filter(int tab_size = 8)
        : tab_size_(tab_size), col_no_(0), spaces_(0)
    { 
        assert(tab_size > 0); 
    }
    template<typename Sink>
    bool put(Sink& dest, int c);
    template<typename Sink>
    void close(Sink&);
private:
    template<typename Sink>
    bool put_char(Sink& dest, int c);
    int  tab_size_;
    int  col_no_;
    int  spaces_;
};
} } } // End namespace boost::iostreams:example

Функция имплементации помощника<put_char>такая же, как у<line_wrapping_output_filter::put_char>: она записывает данный символ в<std::cout>и увеличивает номер столбца, если только символ не является новой линией, и в этом случае номер столбца сбрасывается.

    template<typename Sink>
    bool put_char(Sink& dest, int c)
    {
        if (!iostreams::put(dest, c))
            return false;
        if (c != '\n')
            ++col_no_;
        else
            col_no_ = 0;
        return true;
    }

При помощи<put_char>можно реализовать<put>следующим образом:

    template<typename Sink>
    bool put(Sink& dest, int c)
    {
        for (; spaces_ > 0; --spaces_)
            if (!put_char(dest, ' '))
                return false;
        if (c == '\t') {
            spaces_ = tab_size_ - (col_no_ % tab_size_) - 1;
            return this->put(dest, ' ');
        } 
        return put_char(dest, c);
    }

Реализация начинается с попытки написать любые космические символы, оставшиеся от ранее встречавшихся вкладок. В случае успеха исследуется данный персонаж<c>. Если<c>не является символом вкладки, он пытается написать его<dest>. В противном случае он вычисляет количество пробелов, которые должны быть вставлены, и называет себя рекурсивно. Использование рекурсии здесь избавляет нас от необходимости уменьшать переменную члена<spaces_>в двух разных точках кода.

Обратите внимание, что после того, как столкнется персонаж вкладки, он вернется ложным, пока не будут написаны все связанные космические символы.

Как обычно, функция<close>сбрасывает состояние фильтра:

    void close(Source&)
    {
        col_no_ = 0;
        spaces_ = 0;
    }

Статья Tutorial раздела может быть полезна для разработчиков на c++ и boost.




Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.



:: Главная :: ::


реклама


©KANSoftWare (разработка программного обеспечения, создание программ, создание интерактивных сайтов), 2007
Top.Mail.Ru

Время компиляции файла: 2024-08-30 11:47:00
2025-07-05 10:42:07/0.0071139335632324/0