Изменение поведения двойных кавычек при >> потоке строки - PullRequest
5 голосов
/ 15 января 2011

Вот что я пытаюсь сделать:

говорят, что у меня есть струнный поток.Тогда я << "\"hello world\" today";

тогда, когда я делаю

sstr >> myString1 >> myString2;

, я бы хотел, чтобы myString1 имел "hello world", а myString2 имел бы "today"

способ, возможно, с помощью манипулятора, чтобы достичь этого?

Спасибо

Ответы [ 7 ]

5 голосов
/ 15 января 2011

Краткий ответ: Нет

Длинный ответ:
Там нет манипуляций, которые сделают это для вас.

Альтернативный ответ:

Вы могли бы написать свой собственный тип, который мог бы использоваться вместе с операторами потока, выполняющими эту задачу.

#include <string>
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>


class QuotedWord
{
    public:
        operator std::string const& () const { return data;}

    private:
        std::string     data;
      friend std::ostream& operator<<(std::ostream& str, QuotedWord const& value);
      {
        return str << value.data;
      }
      friend std::istream& operator>>(std::istream& str, QuotedWord& value);
      {
        char x;
        str >> x;
        if ((str) && (x == '"'))
        {
            std::string extra;
            std::getline(str, extra, '"');
            value.data = std::string("\"").append(extra).append("\"");
        }
        else
        {
            str.putback(x);
            str >> value.data;
        }
        return str;
      }
};

Тогда его можно использовать как обычно.

int main()
{
    QuotedWord  word;

    std::cin >> word;
    std::cout << word << "\n";

    // Easily convertible to string
    std::string tmp = word;
    std::cout << tmp << "\n"

    // because it converts to a string easily it can be used where string is needed.
    std::vector<std::string>   data;

    std::copy(std::istream_iterator<QuotedWord>(std::cin),
              std::istream_iterator<QuotedWord>(),

              // Notice we are using a vector of string here.
              std::back_inserter(data)
             );
}

> ./a.out
"This is" a test    // Input
"This is"           // Output
"This is"
4 голосов
/ 15 января 2011

номер

Вам нужно либо изменить тип потока (и, следовательно, семантику синтаксического анализа), либо использовать свой собственный тип строки (и, следовательно, изменить семантику синтаксического анализа в своей перегруженной операции >>).

Вместо этого попробуйте написать функцию, похожую на getline, которая анализирует возможное цитируемое «слово» из потока:

getqword(sstr, myString1);
getqword(sstr, myString2);
if (sstr) { /* both succeeded */ }

Обратите внимание, что ввод в std :: string уже заканчивается в пробеле, поэтому вам нужно только обработать заглядывание вперед для кавычки, а затем обработать крайние случаи, которых много:

  • escape (кавычки внутри кавычек)
    • три распространенных стиля: запрещены, обратная косая черта и двойные кавычки; у каждого есть свои преимущества и недостатки
  • охватывающий несколько строк (можно \ n включить?)
    • это часто ошибка с данными, поэтому в некоторых случаях ее запрещение может оказать большую помощь
  • что происходит, если цитируемое слово заканчивается рядом с другим словом?
    • "\"hello world\"today"
  • пропустить начальные пробелы?
    • в отличие от getline, имеет смысл соблюдать флаг skipws потока, но я мог видеть, что в редких случаях он идет другим путем
    • Часовой istream позаботится об этом за вас
  • не забудьте использовать черты и локаль потока или использовать методы, которые уже делают это!
    • или документируйте свои предположения
2 голосов
/ 15 января 2011

Не напрямую, вам нужен класс-обёртка, который оканчивается там, где вы хотите.

struct QuotedStringReader
{
   std::string& str;
   QuotedStringReader( std::string& s ) : str( s ) {}
};

std::istream operator>>( std::istream&, const QuotedStringReader& qsr );

std::string s, s2;
stream >> QuotedStringReader( s ) << s2;

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

На самом деле, поскольку вы, вероятно, не знаете, что собираетесь читать, вы можете просто назвать его «TokenReader», который читает все, что вы определяете как «токен».

1 голос
/ 15 января 2011

Неа. Не совсем так. Вы можете создать "сильный typedef" для строки и разработать новый оператор >> для него, который будет вести себя таким образом.

0 голосов
/ 09 октября 2018

В с ++ 14

#include <iostream>
#include <iomanip>
#include <sstream>

int main()
{
    std::stringstream ss;
    std::string in = "String with spaces, and embedded \"quotes\" too";
    std::string out;

    ss << std::quoted(in);
    std::cout << "read in     [" << in << "]\n"
              << "stored as   [" << ss.str() << "]\n";

    ss >> std::quoted(out);
    std::cout << "written out [" << out << "]\n";
}

Выход:

read in     [String with spaces, and embedded "quotes" too]
stored as   ["String with spaces, and embedded \"quotes\" too"]
written out [String with spaces, and embedded "quotes" too]

* Источник: https://en.cppreference.com/w/cpp/io/manip/quoted

0 голосов
/ 15 января 2011

Вы можете перегрузить оператор входного потока и включить туда семантику разбора.

std::istream& operator>>(std::istream& is, std::string& out)
{
    char c;
    is >> c;
    if (c == '\"')
    {
        std::getline(is, out, '\"');
        return is;
    }
    else
    {
        is.putback(c);
        return std::operator >>(is, out);
    }
}

int main()
{
    std::istringstream iss("\"hello world\" today");
    std::string test;
    while (iss >> test)
        std::cout << test << std::endl;
}
0 голосов
/ 15 января 2011

Это невозможно.Это потому, что если вы посмотрите на реализацию operator>> для basic_istream, которая фактически вызывается, когда вы делаете sstr >> myString1, вы увидите это внутри цикла for:

else if (_Ctype_fac.is(_Ctype::space,_Traits::to_char_type(_Meta)))
   break;// whitespace, quit

Значит,как только вы получите «пробел», выход.Поэтому вы не можете продолжать добавлять символы в myString1 после получения пробела.

Обратите внимание, что это реализация MSVC ++, но я уверен, что эквивалент вы найдете во всех реализациях!

...