« quoted, szablon funkcji, C++ »
quoted - Manipulator standardowych strumieni wejścia/wyjścia służący do umieszczania i wyjmowania tekstu z cytatu. (szablon funkcji)
Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?
Zarejestruj się!
Hasło nie zostało zweryfikowane
Niniejsze hasło zostało opracowane, jednak nie zostało ono zweryfikowane przez administrację serwisu. Jeżeli znalazłeś błędy merytoryczne w niniejszym dokumencie, prosimy o ich zgłoszenie na forum w dziale Znalezione błędy.
Opracował: baziorek
« Standard C++14 »

quoted

[szablon funkcji] Manipulator standardowych strumieni wejścia/wyjścia służący do umieszczania i wyjmowania tekstu z cytatu.

Składnia

C/C++
#include <iomanip>

namespace std
{
    template < template CharT >
    /*niewyspecyfikowany*/ quoted( const CharT * s, CharT delim = CharT( '"' ), CharT escape = CharT( '\\' ) );
   
    template < template CharT, template Traits, template Allocator >
    /*niewyspecyfikowany*/ quoted( const std::basic_string < CharT, Traits, Allocator >& s, CharT delim = CharT( '"' ), CharT escape = CharT( '\\' ) );
   
    template < template CharT, template Traits, template Allocator >
    /*niewyspecyfikowany*/ quoted( std::basic_string < CharT, Traits, Allocator >& s, CharT delim = CharT( '"' ), CharT escape = CharT( '\\' ) );
}

Parametry szablonu

ParametrOpis
CharTtyp obsługiwanych znaków
Traitstyp dostarczający cechy typu dla znaku
Allocatortyp odpowiadający za przydzielanie i zwalnianie pamięci

Argumenty

ArgumentOpis
stekst do wstawienia lub wyjęcia z cytatu
delimznak początku i końca tekstu, domyślnie "
escapeznak ucieczki, domyślnie \

Zwracana wartość

Nie jest wyspecyfikowana w standardzie wartość zwracana, natomiast np. gcc implementuję funkcje jako zwracającą obiekt tymczasowy posiadający operatory strumienia
std::basic_ostream
 i
std::basic_istream

Opis szczegółowy

Manipulator standardowych strumieni wejścia/wyjścia służący do umieszczania i wyjmowania tekstu z cytatu. Innymi słowy manipulator zadany tekst umieszcza w odpowiednie znaki separatora (domyślnie ") na początku oraz na końcu tekstu, jednocześnie poprzedzając te znaki separatora odpowiednim znakiem ucieczki (domyślnie \ ).

Działanie std::quoted()

Umieszczanie tekstu wewnątrz cytatu

W tej sytuacji zachowanie manipulatora jest zgodnie z konceptem
FormattedOutputFunction
.
Zachowanie szczegółowo wygląda tak:
  • Na początku do strumienia jest umieszczany znak
    delim
  • Następnie do strumienia są wrzucane wszystkie znaki sekwencji, z tą różnicą, że znaki
    delim
     są poprzedzane przez znak
    escape
  • Na koniec znak
    delim
     jest dodawany do strumienia
  • Jeśli długość zacytowanego tekstu jest mniejsza niż długość strumienia wyjściowego wtedy miejsce jest wypełniane kopiami znaku wypełniającego celem wypełnienia całej przestrzeni. Od której strony następuje wypełnianie zależy czy użyjemy:
    ios_base::left
     czy
    ios_base::right

Wyjmowanie tekstu z cytatu

Jeśli pierwszy znak nie jest równy
delim
 to zwyczajnie tekst jest drukowany bez zmian.
W przeciwnym razie
  • Flaga
    skipws
     jest wyłączana
  • Zawartość s jest czyszczona
    s.clear();
  • Poszczególne znaki są wrzucane jeden za drugim, natomiast znalezione znaki
    escape
     są pomijane. Operacja jest kontynuowana do czasu znalezienia wczytania ze strumienia, lub do czasu znalezienia znaku
    delim
     niepoprzedzonego
    escape
  • Pominięcie ostatniego znaku
    delim
  • Przywrócenie oryginalnej wartości flagi
    skipws

Dodatkowe informacje

W standardzie C++17 jest przewidziana dodatkowe przeciążenie tego manipulatora:
C/C++
template < typename CharT, typename Traits >
/*niewyspecyfikowany*/ quoted( std::basic_string_view < CharT, Traits > s, CharT delim = CharT( '"' ), CharT escape = CharT( '\\' ) );

Rzucane wyjątki

W razie błędu funkcji
operator >>()
 i
operator <<()
 zostaje wyrzucony:
std::ios_base::failure
.

Implementacja

Implementacja zainspirowana przez tą dostarczoną do kompilatora gcc w wersji 7.11. W poniższej implementacji pominąłem wyrównywanie tekstu zależnie od flag:
ios_base::left
 czy
ios_base::right
.
C/C++
#include <ios>

template < typename String, typename CharT >
struct QuotedString
{
    String s;
    CharT delim, escape;
   
    QuotedString( String s, CharT delim, CharT escape )
        : s( s )
         , delim( delim )
         , escape( escape )
    { }
   
    QuotedString & operator =( QuotedString & ) = delete;
};


template < typename CharT, typename Traits = std::char_traits < CharT >, typename Alloc = std::allocator < CharT >>
inline auto quoted( const std::basic_string < CharT, Traits, Alloc >& s, CharT delim = CharT( '"' ), CharT escape = CharT( '\\' ) )
{
    return QuotedString < const std::basic_string < CharT, Traits, Alloc >&, CharT >( s, delim, escape );
}

template < typename CharT, typename Traits = std::char_traits < CharT >, typename Alloc = std::allocator < CharT >>
inline auto quoted( const CharT * s, CharT delim = CharT( '"' ), CharT escape = CharT( '\\' ) )
{
    return QuotedString < const std::basic_string < CharT, Traits, Alloc >&, CharT >( s, delim, escape );
}

template < typename CharT, typename Traits = std::char_traits < CharT >, typename Alloc = std::allocator < CharT >>
inline auto quoted( std::basic_string < CharT, Traits, Alloc >& s, CharT delim = CharT( '"' ), CharT escape = CharT( '\\' ) )
{
    return QuotedString < std::basic_string < CharT, Traits, Alloc >&, CharT >( s, delim, escape );
}


template < typename CharT, typename Traits, typename String >
std::basic_ostream < CharT, Traits >& operator <<( std::basic_ostream < CharT, Traits >& os, const QuotedString < String, CharT >& q )
{
    os << q.delim;
    for( CharT c: q.s )
    {
        if( Traits::eq( q.delim, c ) || Traits::eq( q.escape, c ) )
        {
            os << q.escape << c;
        }
        else
        {
            os << c;
        }
    }
    return os << q.delim;
}

template < typename CharT, typename Traits, typename Alloc >
std::basic_istream < CharT, Traits >& operator >>( std::basic_istream < CharT, Traits >& is, const QuotedString < std::basic_string < CharT, Traits, Alloc >&, CharT >& s )
{
    auto c = is.get();
    if( c != s.delim )
    {
        is.unget();
        return is >> s.s;
    }
   
    const auto previousSkipwsFlags = is.flags( is.flags() & ~std::ios_base::skipws );
   
    s.s.clear();
   
    while( true )
    {
        c = is.get();
        if( !is )
        {
            break;
        }
       
        if( Traits::eq( s.delim, c ) )
        {
            break;
        }
        else if( Traits::eq( s.escape, c ) )
        {
            c = is.get();
            if( !is )
            {
                break;
            }
        }
        s.s += c;
    }
   
    is.setf( previousSkipwsFlags );
   
    return is;
}

Przykład

C/C++
#include <iostream>
#include <iomanip>

int main()
{
    const std::string text = R "(Dobry informatyk powiedział: " C++jest najlepszy !", od tej pory jest jeszcze lepszym informatykiem)";
    std::cout << "Oryginalny tekst: " << text << std::endl;
    std::cout << "Cytowany tekst:   " << std::quoted( text ) << std::endl;
   
   
    std::stringstream stream;
    stream << std::quoted( text );
   
    std::string textRestored;
    stream >> std::quoted( textRestored );
    std::cout << "Znowu oryginalny: " << textRestored << std::endl;
}
Standardowe wyjście programu:
Oryginalny tekst: Dobry informatyk powiedział: "C++ jest najlepszy!", od tej pory jest jeszcze lepszym informatykiem
Cytowany tekst:   "Dobry informatyk powiedział: \"C++ jest najlepszy!\", od tej pory jest jeszcze lepszym informatykiem"
Znowu oryginalny: Dobry informatyk powiedział: "C++ jest najlepszy!", od tej pory jest jeszcze lepszym informatykiem

Zagadnienia powiązane

char_traitsStandardowe cechowanie znaków. (szablon klasy)
basic_stringStandardowy kontener C++ dostarczający mechanizmy do łatwej pracy z tekstem, którego znaki są określonego typu. (szablon klasy)
stringPrzechowuje tekst wielobajtowy. Znak jest zdefiniowany za pomocą typu
char
. (alias)
allocatorStandardowy alokator. (szablon klasy)