Как найти в потоке символ

I am working on a piece of arduino code that is using the BlackWidow version with wifi built in. Using the WiServer.h library, I’m using the SimpleClient.pde example with mods to send a call to a webserver that will simply return an integer — 0, 1, or 2. The end goal is to turn on a pin for the proper red, green, or yellow of a stoplight. The integers represent the aggregate state of our Hudson CI.

I’m a PHP lazy bastard, and pointers scare me. The code I am working with is

// Function that prints data from the server
void printData(char* data, int len) {

  // Print the data returned by the server
  // Note that the data is not null-terminated, may be broken up into smaller packets, and 
  // includes the HTTP header. 
  while (len-- > 0) {
    Serial.print(*(data++));
  }
}

printData() is the callback of the call to the webserver, and when run it sends the following to the serial monitor (this is 3 loops, no newline before new output):

HTTP/1.1 200 OK
Date: Thu, 10 Feb 2011 17:37:37 GMT
Server: Apache/2.2.13 (Unix) mod_ssl/2.2.13 OpenSSL/0.9.8k DAV/2 PHP/5.2.11
X-Powered-By: PHP/5.2.11
Content-Length: 1
Connection: close
Content-Type: text/html

0HTTP/1.1 200 OK
Date: Thu, 10 Feb 2011 17:37:45 GMT
Server: Apache/2.2.13 (Unix) mod_ssl/2.2.13 OpenSSL/0.9.8k DAV/2 PHP/5.2.11
X-Powered-By: PHP/5.2.11
Content-Length: 1
Connection: close
Content-Type: text/html

0HTTP/1.1 200 OK
Date: Thu, 10 Feb 2011 17:37:58 GMT
Server: Apache/2.2.13 (Unix) mod_ssl/2.2.13 OpenSSL/0.9.8k DAV/2 PHP/5.2.11
X-Powered-By: PHP/5.2.11
Content-Length: 1
Connection: close
Content-Type: text/html

0

The part that I need to identify is the 0, which could also be 1 or 2.

Instead of printData(), this function will become turnOnAppropriateLight() or something, by simply setting a pin to HIGH. This will then activate a relay, to power the corresponding LED array.

Now that I’ve written this up it looks like I just need to keep the last character around and do a switch based on the value. The *(data++) is the confusing part even though I know it’s incrementing a pointer index…I’m just not sure how to go directly to the last char in that index. No need for this looping to spit out the result.

arduino and 4-relay board
enter image description here

Работа с потоками в С++

9.1. Структура стандартной библиотеки ввода-вывода.

В языке программирования С++ стандартная библиотека ввода-вывода организована как иерархия шаблонов классов. Эта библиотека содержит два стандартных множества конкретизированных шаблонов этой иерархии: одно для работы с символами типа char, другое для работы с символами типа wchar_t. Классы для работы с символами типа wchar_t имеют те же имена, что и классы для работы с символами типа char, но с префиксом w.

Ниже перечислены заголовочные файлы, которые содержат интерфейсы классов из стандартной библиотеки ввода-вывода:

<ios> ios_base, ios
<istream> istream
<ostream> ostream
<iostream> iostream, cin, cout, cerr
<fstream> ifstream, fstream, ofstream, filebuf
<sstream> istringstream, stringstream, ostringstream, stringbuf
<streambuf> streambuf

9.2. Классы ios_base и ios.

В классах ios_base и ios определены методы, которые являются общими для входных и выходных потоков. Класс ios_base содержит методы, которые не зависят от параметров шаблона. Наоборот, класс ios содержит шаблонно-зависимые методы. Объект класса ios_base не может быть создан непосредственно, а только в наследуемых классах.

Объекты типа ios_base поддерживают следующую информацию о состоянии потока.

Информацию о форматировании ввода-вывода:

— флаги форматирования,

— длину полей ввода-вывода,

— разрешимость дисплея.

Информацию о состоянии потока:

— состояние ошибки,

— маску исключений,

Другая информация:

— стек вызовов callback функций при наступлении некоторых событий,

— внутренний массив с элементами типа long,

— внутренний массив с элементами типа void*.

Перечислим некоторые методы класса ios_base:

flags                       чтение-установка флагов форматирования,

precision               чтение-установка точности double,

setf                         установка некоторых флагов форматирования,

unsetf                    сброс флагов форматирования.

Например, в следующей программе показано как установить в качестве базовой 16 с/с.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

#include <iostream>

using namespace std;

int main ()

{            

// установить 16c/c в качестве базовой

cout.setf ( ios_base::hex, ios_base::basefield );

// показывать базу

cout.setf ( ios_base::showbase );

cout << 100 << endl;

// не показывать базу

cout.setf ( 0, ios_base::showbase );

cout << 100 << endl;

return 1;

}

Класс ios поддерживает следующую информацию о потоке:

—          символ заполнитель,

—          указатель на поток вывода, связанный с объектом типа ios,

—          указатель на объект типа streambuf, связанный с объектом типа ios.

Перечислим некоторые методы класса ios:

operator!               возвращает true, если установлен любой из флагов failbit или badbit, иначе возвращает false,

bad                        возвращает true в случае неустранимой ошибки ввода-вывода,

clear                       сбрасывает управляющие состояния,

eof                         проверяет на конец файла,

exception              читает-устанавливает маску исключений,

fail                          проверяет на ошибку, исключая конец файла,

fill                           читает-устанавливает символ заполнитель,

good                      возвращает true, если нет ошибок,

rdstate                   читает управляющие состояния,

setstate                  устанавливает управляющие состояния.

Кроме того, класс ios поддерживает режимы работы потока, которые задаются следующими флагами:

ios::app                 данные всегда записываются в конец файла,

ios::ate                  первый байт записывается в конец файла, остальные байты с текущей позиции,

ios::binary            бинарный файл,

ios::in                    входной файл,

ios::nocreate        открыть существующий файл, если файла нет, то ошибка,

ios::noreplace      открыть новый файл, если файл уже есть, то ошибка,

ios::out                  выходной файл,

ios::trunc              файл открывается и его содержимое стирается,

Например, в следующей программе показано, как проверить, успешно ли открыт файл.

#include <iostream>

#include <fstream>

using namespace std;

int main ()

{

ifstream in;

in.open («test.txt»);

if (!in)

    cerr << «Error: open file ‘test.txt’ failed.» << endl;

return 0;

}

9.3. Потоки вывода.

Потоки вывода создаются на базе класса ostream, который обеспечивает методы для записи данных в буфер потока. Перечислим основные методы класса ostream:

operator<<           форматированный вывод данных в поток,

flush                      очищает буфер,

put                         выводит символ,

seekp                     устанавливает позицию для функции put,

tellp                        читает позицию указателя для функции put,

write                       пишет последовательность байтов,

От класса ostream наследуются класс ofstream, который содержит дополнительные методы:

open                      открыть файл,

close                      закрыть файл,

is_open                 проверка открыт ли файл.

Сейчас приведем прототипы этих функций и примеры их использования.

1. Функции open, close и is_open имеют следующие прототипы:

void open ( const char * filename, openmode mode = out | trunc );

void close ( );

bool is_open ( );

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

Например, следующая программа добавляет предложение в конец текстового файла и показывает, как использовать вышеперечисленные функции.

#include <iostream.h>

#include <fstream>

using namespace std;

int main ()

{

ofstream out;

out.open («test.txt», ofstream::out | ofstream::app);

if (out.is_open())

    out << «This sentence is appended to the file content.n»;

else

   cerr << «Open file failed.» << endl;

out.close();

return 0;

}

2. Функцияflush очищает буфер. Эта функция имеет следующий прототип:

ostream& flush ( );

Ниже приведен пример использования функции flush. Этот пример также показывает, как можно создавать текстовый файл

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

#include <fstream.h>

int main ()

{

ofstream out(«test.txt»);

for (int n=0; n<100; n++)

{

    out << n << ‘ ‘;

    out.flush();

}

out << ‘n’;                         // переход на новую строку

for (n=0; n<100; n++)

    out << (n+0.1) << ‘ ‘ << flush;

out << endl;                         // переход на новую строку

out.close();

return 0;

}

3. Функция put выводит символ в файл. Эта функция имеет следующий прототип:

ostream& put ( char ch );

В следующем примере показано, как водить символы с консоли и выводить их в файл.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

#include <iostream.h>

#include <fstream.h>

int main ()

{

char ch;

ofstream out(«test.txt»);

cout << «Input chars then input ‘.’ to exit.» << endl;

do

{

    ch = cin.get();

    out.put(ch);

} while (ch!=‘.’);

return 0;

}

4. Функция seekp устанавливает, а функция tellp читает позицию в файле для функции put. Эти функции имеют следующие прототипы:

streampos tellp ( );

ostream& seekp ( streampos pos );

где pos — новая позиция в потоке;

ostream& seekp ( streamoff off, ios_base::seekdir dir );

где параметры имеют следующее назначение:

off           смещение в потоке относительно позиции, указанной в параметре dir.

dir          направление поиска позиции, может принимать одно из следующих значений:

  • ios_base::beg – поиск от начала файла;
  • ios_base::cur  — поиск от текущей позиции;
  • ios_base::end – поиск от конца файла.

Ниже приведен пример использования этих функций.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

#include <fstream.h>

int main ()

{

long pos;

ofstream out;

out.open («test.txt»);

out << «This is a string.» << endl;

pos=out.tellp();

out.seekp (pos 11);

out << «an example.»;

out.close();

return 0;

}

5. Функция write пишет последовательность символов (байтов) в файл. Эта функция имеет следующий прототип:

ostream& write ( const char* s , size n );

где s указывает на область памяти, из которой данные записываются в файл, а n – количество записываемых символов (байтов). Отметим, что эта функция используется для записи данных в бинарные файлы, то есть содержимое области памяти записывается в файл без изменения. Ниже приведен пример создания бинарного файла, используя функцию write.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

#include <iostream.h>

#include <fstream.h>

struct emp

{

    int code;

    char name[20];

    double salary;

};

int main()

{

ofstream out;                      // выходной поток

struct emp s;                        // для записей файла

// открываем выходной поток в бинарном режиме

out.open(«demo.bin», ofstream::binary);

if(!out)

{

    cerr << «Open file failed.» << endl;

    return 1;

}

cout << «Input code, name and salary.» << endl;

cout << «Press Ctrl+z to exit.» << endl;

cout << ‘>’;

// вводим первую запись с консоли

cin >> s.code >> s.name >> s.salary;

while (!cin.eof())

{       

    // пишем запись в файл

    out.write((const char*)&s, sizeof(struct emp));

    cout << ‘>’;

    // вводим следующие записи с консоли

    cin >> s.code >> s.name >> s.salary;

}

// закрываем выходной поток

out.close();

return 0;

}

От класса ostream также наследуются класс ostringstream, который обеспечивает интерфейс для работы со строками.

Класс ostringstream содержит дополнительный метод:

str – чтение и запись строки в поток.

6. Функция str выполняет запись и чтение строки в поток. Эта функция имеет следующий прототип:

string str ( ) const                     чтение строки из потока

void str ( string & s );                запись строки s в поток

Например, в следующей программе показано, как ввести строку в поток типа ostringstream, а затем прочитать его содержимое в объект типа string.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

#include <iostream>

#include <sstream>

#include <string>

using namespace std;

int main ()

{

ostringstream oss;

string s;

oss.str(«Sample string_1.»);

s = oss.str();

cout << s << endl;

oss << «Sample string_2.»;

s = oss.str();

cout << s << endl;

return 0;

}

1.4. Потоки ввода.

Потоки ввода являются объектами класса istream, который обеспечивает методы для чтения информации из буфера потока. Перечислим основные методы класса istream:

operator >>          форматированный ввод,

gcount                   возвращает количество символов, прочитанных последней операцией ввода,

get                          ввод символа,

getline                    ввод строки,

ignore                    удаление символов из буфера,

peek                       читает символ, но не удаляет его из буфера,

putback                возвращает символ в буфер,

read                       читает блок данных,

seekg                     устанавливает указатель позиции файла для метода get,

sync                       синхронизирует буфер потока с внешним устройством,

tellg                        получает указатель позиции файла для метода get,

unget                     возвращает символ в поток,

От класса istream наследуется класс ifstream, который обеспечивает интерфейс для работы с файлами. Класс ifstream содержит дополнительные методы:

open                      открыть файл,

close                      закрыть файл,

is_open                 проверить, открыт ли файл.

Как работать с этими функциями, было показано в предыдущем параграфе. Сейчас же подробно рассмотрим работу с функциями класса istream.

1. Функция gcount возвращает количество символов, прочитанных последней не форматирующей операцией ввода. Эта функция имеет следующий прототип:

streamsize gcount ( ) const;

К не форматирующим операциям ввода относятся следующие операции: get, getline, ignore, read и readsome. Пример использования функции gcount показан в следующей программе:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

#include <iostream>

#include <string>

using namespace std;

int main ()

{

char line[80];

int length;

cout << «Input a string: « << endl;

cin.getline(line, 80);

length = cin.gcount();

cout << «String length = « << length1 << endl;

return 0;

}

2. Функция get вводит символ из входного потока. Эта функция имеет следующий прототип:

int get();

возвращает символ, извлеченный из потока;

istream& get (char& c );

извлекает символ из потока и сохраняет его в переменной с;

istream& get (char* s, streamsize n, char delim = ‘n’ );

вводит из потока символы и записывает их в массив s, ввод символов прекращается в следующих случаях:

—          если введен (n-1) символ;

—          если в потоке встретился символ разделитель delim, сам символ разделитель из потока не извлекается;

—          файл закончился раньше, чем прочитан (n-1) символ.

После записи прочитанных символов в массив s функция get записывает в этот массив пустой символ NULL, отмечающий конец строки. Ниже приведена программа, которая распечатывает содержимое текстового файла.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

#include <iostream>

#include <fstream>

using namespace std;

int main ()

{

ifstream in;

in.open («test.txt», ifstream::in);

while (in.good())

    cout << (char) in.get();

cout << endl;

in.close();

return 0;

}

А теперь приведена программа, которая читает символы из входного потока, используя функцию get.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

#include <iostream.h>

int main ()

{

char c;

char a[3];

cout << «Input a char: «;

c = cin.get();

cout << c << endl;

cin.get();                                               // удаляем символ конца строки

cout << «Input a char: «;

cin.get(c);

cout << c << endl;

cin.get();                                               // удаляем символ конца строки

cout << «Input a string: «;

cin.get(a, 3);

cout << endl << «The first two symbols: «;

cout << a << endl << endl;

return 0;

}

3. Функция getline вводит строки из файла. Эта функция имеет следующий прототип:

istream& getline (char* s, streamsize n, char delim = ‘n’);

вводит из потока символы и записывает их в массив s, ввод символов прекращается в следующих случаях:

—          если введен (n-1) символ;

—          если в потоке встретился символ разделитель delim, причем сам символ разделитель извлекается из потока, но не записывается в массив s;

—          файл закончился раньше, чем прочитан (n-1) символ.

После записи прочитанных символов в массив s функция getline записывает в этот массив пустой символ NULL, отмечающий конец строки. Ниже приведена программа, которая вводит строки из потока и распечатывает их на консоли.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

#include <iostream.h>

int main ()

{

char line[80];

cout << «Input strings. « << endl;

cout << «To exit press CTRL+Z.» << endl;

cout << ‘>’;

while (!cin.eof())

{

    cin.getline(line, 80);

    cout << ‘ ‘ << line << endl;

    cout << ‘>’;

}

return 0;

}

4. Функция ignore удаляет символы из буфера потока. Эта функция имеет следующий прототип:

istream& ignore ( streamsize n = 1, int delim = EOF );

где n – количество символов, которые необходимо удалить из потока, а delim – это символ ограничитель. Функция удаляет символы из потока до тех пор, пока не удалит n символов или не встретит символ разделитель. Например, в следующей программе выводятся только первые символы введенных слов.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

#include <iostream>

using namespace std;

int main ()

{

char c;

cout << «Input a word: «;

c = cin.get();

cin.ignore(256,‘n’);

cout << «The first letter is: « << c << endl;

cout << «Input another word: «;

cin.ignore();

c = cin.get();

cin.ignore(256,‘n’);

cout << «The second letter is: « << c << endl;

return 0;

}

5. Функция peek читает символ, но не удаляет его из буфера. Эта функция имеет следующий прототип:

int peek ( );       возвращает прочитанный символ, а если файл закончился или в потоке произошла ошибка, то возвращает EOF.

Ниже приведена программа, в которой используется функция peek.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

#include <iostream>

using namespace std;

int main ()

{

char c;

int n;

char s[256];

cout << «Enter a number or a word: «;

c = cin.peek();

if ( (c >= ‘0’) && (c <= ‘9’) )

{

    cin >> n;

    cout << «It is a number: « << n << endl;

}

else

{

    cin >> s;

    cout << «It is a word: « << s << endl;

}

return 0;

}

6. Функция putback возвращает символ в буфер. Эта функция имеет следующий прототип:

istream& putback (char ch );     если введенный символ совпадает с символом ch, то функция возвращает его в буфер ввода, иначе поведение функции непредсказуемо.

Использование функции putback показано в следующей программе.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

#include <iostream>

using namespace std;

int main ()

{

char c;

int n;

char s[256];

cout << «Enter a number or a word: «;

c = cin.get();

cin.putback (c);

if ( (c >= ‘0’) && (c <= ‘9’) )

{

    cin >> n;

    cout << «It is a number: « << n << endl;

}

else

{

    cin >> s;

    cout << » It is a word: « << s << endl;

}

return 0;

}

7. Функция read читает блок данных из файла и имеет следующий прототип:

istream& read (char* s, streamsize n );

где s указывает на область памяти, в которую данные читаются из файла, а n – количество читаемых символов (байтов). Отметим, что эта функция используется для чтения данных из бинарных файлов, то есть содержимое файла без изменения читается в область памяти. Ниже приведен пример чтения записей бинарного файла, используя функцию read.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

// чтение бинарного файла

#include <iostream.h>

#include <fstream.h>

struct emp

{

    int code;

    char name[20];

    double salary;

};

int main()

{

ifstream in;                     // выходной поток

struct emp s;                    // для записей файла

unsigned i;                      // номер записи

// открываем входной поток в бинарном режиме

in.open(«demo.bin»);

if(!in)

{

    cout << «Open file failed.n»;

    return 1;

}

cout << «Press Ctrl+z to exit.n»;

// читаем индекс

cout << «Input an index: «;

cin >> i;

while (!cin.eof())

{

    // устанавливает указатель на нужную запись

    in.seekg(i*sizeof(struct emp));

    // читаем запись из файла

    in.read((char*)&s, sizeof(struct emp));

    if (!in.good())

    {

        cout << «The wrong index.n»;

        cout << «Input an index: «;

        cin >> i;

        in.clear();                              // очищаем ошибку

        continue;

    }

    // выводим запись на консоль

    cout << «tcode = « << s.code

    << » name = « << s.name

    << » sal = « << s.salary << endl,

    // читаем индекс

    cout << «Input an index: «;

    cin >> i;

}

// закрываем входной поток

in.close();

return 0;

}

8. Функция seekg устанавливает указатель позиции файла для метода get, а функция tellg получает указатель позиции файла для метода get. Эти функции имеют следующие прототипы:

istream& seekg ( streampos pos );        устанавливает позицию файла на значение pos, тип streampos эквивалентен типу long.

istream&  seekg ( streamoff off, ios_base::seekdir dir ); сдвигает позицию файла на значение off относительно значения параметра dir, который может принимать следующие значения:

  • ios_base::beg            смещение относительно начала файла;
  • ios_base::cur            смещение относительно текущей позиции;
  • ios_base::end            смещение относительно конца файла.

streampos tellg ( );       возвращает указатель позиции файла для функции get, тип streampos эквивалентен типу long.

Ниже приведена программа, которая демонстрирует использование вышеуказанных функций.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

// чтение файла в память

#include <iostream.h>

#include <fstream.h>

struct emp

{

    int code;

    char name[20];

    double salary;

};

int main ()

{

int length;

emp* buffer;

ifstream in;

in.open(«demo.bin», ios::binary);

if (!in)

{

    cout << «Open file failed» << endl;

    return 1;

}

// определеям длину файла

in.seekg(0, ios::end);

length = in.tellg();

in.seekg(0, ios::beg);

// распределяем память под файл

buffer = (emp*) new char[length];

// читаем файл

in.read((char*)buffer,length);

in.close();

// выводим содержимое на консоль

for (int i=0; i<length/(int)sizeof(emp); ++i)

    cout << buffer[i].code << ‘ ‘

    << buffer[i].name << ‘ ‘

    << buffer[i].salary << endl;

return 0;

}

9. Функция sync                 синхронизирует буфер потока с внешним устройством. Эта функция имеет следующий прототип:

int sync ( );

Как работает эта функция, и что такое синхронизация буфера потока с внешним устройством смотри в параграфе 1.6.

10. Функция unget возвращает в поток символ, предварительно извлеченный из потока. Эта функция имеет следующий прототип:

int unget();        возвращает символ, извлеченный из потока.

Ниже приведена программа, в которой показано использование функции unget.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

#include <iostream>

using namespace std;

int main ()

{

char c;

int n;

char s[256];

cout << «Enter a number or a word: «;

c = cin.get();

cin.unget();

if ( (c >= ‘0’) && (c <= ‘9’) )

{

    cin >> n;

    cout << «It is a number: « << n << endl;

}

else

{

    cin >> s;

    cout << «It is a word: « << s << endl;

}

return 0;

}

От класса istream наследуется класс istringstream, который обеспечивает интерфейс для работы со строками. Класс istringstream содержит дополнительный метод:

str                           чтение или запись строки в поток.

11. Функция str для записи и чтения строки в поток.

Прототипы этой функции были рассмотрены в предыдущем параграфе пункт 6. Сейчас же приведем только программу, в которой показано, как записать строку в поток типа istringstream, а затем вывести содержимое этого потока.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

#include <iostream>

#include <sstream>

#include <string>

using namespace std;

int main ()

{

int n;

istringstream iss;

string s = «0 1 2»;

iss.str(s);

for (int i = 0; i < 3; ++i)

{

    iss >> n;

    cout << n + 1 << endl;

}

return 0;

}

1.5. Потоки ввода-вывода.

Потоки ввода-вывода создаются на базе класса iostream, который является производным классом от классов istream и ostream и поэтому наследует все их методы. Для работы с файлами и со строками из класса iostream наследуются соответственно классы fstream и stringstream, которые позволяют, как писать данные в потоки, так и читать данные из потоков. Для наглядного представления отношения наследования между этими классами смотри диаграмму наследования в параграфе 1.1.

Здесь же заметим, что заголовочный файл <iostream> содержит потоки ввода-вывода: cin, cout, cerr и clog, примеры работы с которыми смотри в параграфе 1.8.

1.6. Буферы и синхронизация.

Потоки выполняют обмен данными между прикладной программой и файлом через буферы, которые являются объектами классов filebuf и stringbuf соответственно. Эти классы являются производными от абстрактного класса streambuf. Каждый буфер содержит в зависимости от режима доступа один или два символьных массива: один для ввода, а второй для вывода данных. Каждый поток поддерживает внутренний указатель на буфер. Ввод-вывод данных из буфера в файл или в строку называется синхронизацией буфера с внешним устройством ввода-вывода. Синхронизация буфера с внешним устройством может выполняться неявно или явно. Неявно синхронизация выполняется в случае закрытия файла или заполнения буфера. Для явной синхронизации используют манипуляторы flush и endl или функцию sync.

Например, в следующей программе показана синхронизация буфера с входным потоком.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

#include <iostream>

using namespace std;

int main ()

{

char a, b;

cout << «Enter a word: «;

a = cin.get();

cin.sync();

cout << «Enter another word: «;

b = cin.get();

cout << «The first word began by: « << a << endl;

cout << «The second word began by: « << b << endl;

return 0;

}

1.7. Манипуляторы.

Манипулятором называется глобальная функция, которая изменяет поток. Манипуляторы предназначены для включения в последовательность операторов ввода или вывода и могут изменять состояние потока, управляя его флагами. Манипуляторы подразделяются на две группы: простые манипуляторы и параметризованные манипуляторы.

Простые манипуляторы не требуют аргументов. Ниже перечислены простые манипуляторы:

endl        помещает в выходной поток символ ‘n’ и вызывает манипулятор flush,

ends       помещает в поток символ ‘’,

flush       освобождает поток,

dec         устанавливает 10 c/c,

hex         устанавливает 16 c/c,

oct          устанавливает 8 c/c,

ws           игнорирует при вводе ведущие пробелы.

Манипуляторы с аргументами называются параметризованными. Ниже перечислены параметризованные манипуляторы, которые объявлены в заголовочном файле <iomanip>:

resetiosflags         сбрасывает флаги форматирование,

setiosflags             устанавливает флаги форматирования,

setbase                  устанавливает систему счисления,

setfill                      устанавливает символ заполнитель,

setprecision          устанавливает точность для плавающих чисел,

setw                       устанавливает ширину поля для символа заполнителя.

Можно написать свой манипулятор. Например, следующая функция является манипулятором, который выполняет переход на новый абзац.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

#include <iostream.h>

ostream& tabl(ostream& out)

{

    out << ‘n’ << ‘t’;

    return out;

}

int main()

{

cout << «This is a test for the manipulator tabl»

<< tabl

<< «The end of the test» << endl;

return 0;

}

9.8. Стандартные потоки ввода-вывода.

Стандартный входной поток cin является объектом класса istream и по умолчанию связан с клавиатурой. Стандартные потоки cout, cerr и clog являются объектами класса ostream и по умолчанию связаны с дисплеем. Для работы со стандартными потоками в программу необходимо включить заголовочный файл <iostream>. Например,

#include <iostream.h>

int main()

{

int n = 0;

clog << «n = « << n << endl;

++n;

clog << «n = « << n << endl;

return 1;

}

А. П. Побегайло

04.02.2014

Потоки в C++ / Alexey Nurgaliev


Потоки вывода (ostream)

Для вывода данных используеся оператор <<. Этот опрератор определен для всех встроенных типов C++ и некоторых классов, входящих в стандартную библиотеку. Для вывода перевода строки можно использовать специальный объект endl.

Примеры использования потока вывода:

int i = 10;
char c = 'A';
char cs[] = "C string";
bool b = true;
double d = 3.14159265;
string s = "STL string";

cout << i <<endl;
cout << c << 'B' << endl;
cout << cs << endl << b << endl;
cout << d << endl;
cout << s << endl;

Будет выведено:

10
AB
C string
1
3.14159
STL string

Также оператор << можно использовать и со своими классами, определив для них перегруженный оператор. Например, для структуры Book перегруженный оператор может выглядеть так:

struct Book{
	string title, author;
	int num_pages;
	
	ostream& operator<<(ostream& s){
		return (s << author << " " << title << " (" << num_pages << ")");
	}
};

Некоторые методы класса ostream:

  • put(char c) — записать символ с в поток
  • write(const char* s, streamsize n) — записать первые n элементов массива s в поток (streamsize представляет целое число со знаком, например, int)
  • flush() — записать значение из буфера
  • close() — закрытие потока

Потоки ввода (istream)

Для ввода используется оператор >>. Он также определен для всех встроенных типов и некоторых классов стандартной библиотеки.

Оператор >> также можно определить для своих классов:

istream& operator>>(istream& s)
{
	...
}

Некоторые методы класса istream:

  • get() — считать следующий символ
  • get(char *buf, streamsize n) — считать максимум n-1 символ и поместить в массив buf
  • get(char *buf, streamsize n, char delim) — считывание символов до символа-разделителя delim (разделитель не считывается и остается в потоке)
  • getline(char *buf, streamsize n)
  • getline(char *buf, streamsize n, char delim)
  • peek() — считывает следующий символ, но оставляет его в потоке
  • ignore(streamsize n = 1, int delim = EOF) — извлекает символы из потока до тех пор, пока их число меньше n или пока не встретился символ delim
  • putback(char c) — добавляет символ с в текущую позицию потока
  • unget() — возвращает последний считанный символ в поток

Форматирование

Для управления форматом вывода можно устанавливать специальные флаги потока методом setf(ios_base::fmtflags f). Но удобнее пользоваться манипуляторами — специальными функциями, реализованными в заголочных файлах <istream>, <ostream> (они по умолчанию включены в <iostream>) и <iomanip>.

Основные манипуляторы ввода/вывода:

  • boolalpha — стороковое представление логических значений
  • noboolalpha — числовое представление логических значений
cout << boolalpha << true << endl;
cout << noboolalpha << false;

Выведет:

true
0
  • showbase — включает вывод 0 перед восьмеричными и 0x перед шестнадцатеричными числами
  • noshowbase — выключает вывод 0 и 0x
  • dec — вывод чисел в десятичной системе счисления
  • oct — в восьмеричной
  • hex — в шестнадцатеричной
  • uppercase — заглавные буквы в записи шестнадцатеричных чисел и чисел с плавающей запятой в научной записи
  • nouppercase — строчные буквы в записи чисел
cout << showbase << uppercase;
cout << oct << 0777 << ' ';
cout << hex << 0xABC << endl;
cout << noshowbase << nouppercase;
cout << oct << 0777 << ' ';
cout << hex << 0xABC << endl;

Выведет:

0777 0XABC
777 abc
  • skipws — пропуск символов-разделителей (' ', 't', 'n', и т.п.)
  • noskipws — выключение пропуска разделителей
  • setw(int n) — определяет минимальное количество символов, которые выведутся следующей операцией вывода
  • setfill(char c) — символ-заполнитель
  • left — выравнивание поля по левому краю
  • right — выравнивание поля по правому краю
  • internal — выравнивание поля по ширине
cout << setw(10);
cout << setfill('#');
cout << 1 << endl;
cout << setw(5);
cout << 100 << endl;
cout << left << setw(10) << -100 << endl;
cout << right << setw(10) << -100 << endl;
cout << internal << setw(10) << -100 << endl;

Выведет:

#########1
##100
-100######
######-100
-#######10
  • scientific — научная запись для чисел с плавающей запятой
  • fixed — фиксированная точность для чисел с плавающей запятой
  • setprecision — точность вывода чисел (по умолчанию равна 6)
cout << 1234.5678 << endl;
cout << scientific << 1234.5678 << endl;
cout << fixed << 1234.5678 << endl;

cout << setprecision(4);
cout << 1234.5678 << endl;
cout << scientific << 1234.5678 << endl;
cout << fixed << 1234.5678 << endl;

Выведет:

1234.57
1.234568e+003
1234.567800
1234.5678
1.2346e+003
1234.5678
  • endl — запись n и очистка буфера
  • ends — запись
  • flush — очистка буфера потока
  • ws — прочитать и проигнорировать символы-разделители

Сотояние потока

Каждый поток istream или ostream имеет связанное с ним состояние.

Методы проверки состояния:

  • good() — можно выполнить следующую операцию
  • eof() — конец потока
  • fail() — следующая операция не выполнится
  • bad() — поток испорчен

Стандартные потоки — iostream

Для реализации стандартного ввода/вывода в библиотеку C++ включен заголовочный файл iostream, содержащий следующие предопределенные объекты потоков:

  • cin — стандартный поток ввода (соответствует потоку C stdin)
  • cout — стандартный поток вывода (соответствует stdout)
  • cerr — стандартный поток вывода ошибок (соответствует stderr)
  • clog — стандартный поток вывода журнала (соответствует stderr)

Файловые потоки — fstream

Файловые потоки расположены в заголовочном файле <fstream>. ifstream — поток ввода, ofstream — поток вывода.

Имя файла передается потоку либо в конструкторе, либо через вызов метода open.

ofstream out_1("test1.txt");
ofstream out_2;
out_2.open("test2.txt");

...

out_1.close();
out_2.close();

Строковые потоки — sstream

Строковые потоки расположены в заголовочном файле <sstream>.

istringstream — поток ввода. Строка передается потоку в конструкторе.

ostringstream — поток вывода. Строку-результат возвращает метод str().

string str = "1 2 3";
istringstream iss(str);
ostringstream oss;
int a, b, c;
iss >> a >> b >> c;
oss << a << endl;
oss << setw(5) << setfill('#');
oss << b << endl;
oss << c;
cout << oss.str();

Выведет:

1
####2
3

Есть прочитанный из файла текст в переменной типа String all_text.

В нем есть разделы помеченные вот так:

[f1] Текст какой-то.... [g5] Текст другой.....

Как осуществить поиск по тексту и сохранить (в переменную String part_txt) строки находящиеся между [f1] и [g5]?

Saidolim's user avatar

Saidolim

8,3314 золотых знака26 серебряных знаков48 бронзовых знаков

задан 21 апр 2016 в 6:36

kaaa's user avatar

2

Попробуйте так:

String text = "[f1] Текст какой-то.... [g5] [f1] Текст другой..... [g5]";
Pattern p = Pattern.compile("\[f1\](.+?)\[g5\]");
Matcher m = p.matcher(text);
m.find();
System.out.println(m.group(1));
m.find();
System.out.println(m.group(1));

Вывод:

Текст какой-то.... 
Текст другой..... 

Если необходимо, пробежаться по всему тексту, это очевидно, цикл -> проверка на совпадение.

Nicolas Chabanovsky's user avatar

ответ дан 21 апр 2016 в 7:01

Shwarz Andrei's user avatar

Shwarz AndreiShwarz Andrei

12k1 золотой знак19 серебряных знаков40 бронзовых знаков

1

public String ReturnStr(String m1, String m2, String text, int startIndex)
    {
       int first, second; 
       //не работаем с пустыми строками
       if(m1.length() == 0 || m2.length() == 0 || text.length() == 0) return null;       
       //проверим, не выходит ли стартовый индекс за пределы текста
       if( startIndex < 0 || startIndex > text.length()) return null;       
       //находим первую метку и сдвигаем индекс на длину метки
       first = text.indexOf(m1,startIndex);
       //если начальной метки не нашлось, возвращаем null
       //но можно изменить 2 строки ниже и вести отсчет с начала текста, это по желанию
       if(first < 0)return null;// заменить эту строку
       first += m1.length();//     и эту на if(first < 0) first = 0;       
       //проверим, не является ли метка концом текста
       if(first >= text.length()) return null;       
       //находим вторую метку
       second = text.indexOf(m2, first);
       //если нашли только начальную метку, вырезать весь текст до конца
       if(second < 0)return text.substring(first);
       return text.substring(first, second);
    }

Поиск по любым заданным меткам. А вообще — тут много чего можно улучшить, зависит от решаемой задачи.

ответ дан 21 апр 2016 в 10:16

FoeNicks's user avatar

FoeNicksFoeNicks

2111 серебряный знак10 бронзовых знаков

Я понимаю, что это действительно запоздало, но я просто наткнулся на этот невероятный недостаток в StreamReader сам; тот факт, что вы не можете надежно искать при использовании StreamReader. Лично моя особая потребность в том, чтобы иметь возможность читать символы, но затем «поддерживать», если выполняется определенное условие; это побочный эффект одного из форматов файлов, которые я обрабатываю.

Использование ReadLine() не является опцией, потому что оно полезно только для действительно тривиальных заданий синтаксического анализа. Я должен поддерживать настраиваемые последовательности разделителей строк и строк и поддерживать последовательности разделителей escape-последовательности. Кроме того, я не хочу реализовывать свой собственный буфер, поэтому я могу поддерживать «резервное копирование» и escape-последовательности; это должно быть задание StreamReader.

Этот метод вычисляет фактическую позицию в базовом потоке байтов по запросу. Он работает для UTF8, UTF-16LE, UTF-16BE, UTF-32LE, UTF-32BE и любого однобайтового кодирования (например, кодовых страниц 1252, 437, 28591 и т.д.), Независимо от наличия преамбулы/спецификации. Эта версия не будет работать для кодировок UTF-7, Shift-JIS или других переменных-байтов.

Когда мне нужно искать произвольную позицию в базовом потоке, я прямо устанавливаю BaseStream.Position, а затем вызываю DiscardBufferedData(), чтобы получить StreamReader назад в синхронизации для следующего вызова Read()/Peek().

И дружеское напоминание: не произвольно устанавливайте BaseStream.Position. Если вы разделите символ на две части, вы отмените следующий Read(), а для UTF-16/-32 вы также аннулируете результат этого метода.

public static long GetActualPosition(StreamReader reader)
{
    System.Reflection.BindingFlags flags = System.Reflection.BindingFlags.DeclaredOnly | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.GetField;

    // The current buffer of decoded characters
    char[] charBuffer = (char[])reader.GetType().InvokeMember("charBuffer", flags, null, reader, null);

    // The index of the next char to be read from charBuffer
    int charPos = (int)reader.GetType().InvokeMember("charPos", flags, null, reader, null);

    // The number of decoded chars presently used in charBuffer
    int charLen = (int)reader.GetType().InvokeMember("charLen", flags, null, reader, null);

    // The current buffer of read bytes (byteBuffer.Length = 1024; this is critical).
    byte[] byteBuffer = (byte[])reader.GetType().InvokeMember("byteBuffer", flags, null, reader, null);

    // The number of bytes read while advancing reader.BaseStream.Position to (re)fill charBuffer
    int byteLen = (int)reader.GetType().InvokeMember("byteLen", flags, null, reader, null);

    // The number of bytes the remaining chars use in the original encoding.
    int numBytesLeft = reader.CurrentEncoding.GetByteCount(charBuffer, charPos, charLen - charPos);

    // For variable-byte encodings, deal with partial chars at the end of the buffer
    int numFragments = 0;
    if (byteLen > 0 && !reader.CurrentEncoding.IsSingleByte)
    {
        if (reader.CurrentEncoding.CodePage == 65001) // UTF-8
        {
            byte byteCountMask = 0;
            while ((byteBuffer[byteLen - numFragments - 1] >> 6) == 2) // if the byte is "10xx xxxx", it a continuation-byte
                byteCountMask |= (byte)(1 << ++numFragments); // count bytes & build the "complete char" mask
            if ((byteBuffer[byteLen - numFragments - 1] >> 6) == 3) // if the byte is "11xx xxxx", it starts a multi-byte char.
                byteCountMask |= (byte)(1 << ++numFragments); // count bytes & build the "complete char" mask
            // see if we found as many bytes as the leading-byte says to expect
            if (numFragments > 1 && ((byteBuffer[byteLen - numFragments] >> 7 - numFragments) == byteCountMask))
                numFragments = 0; // no partial-char in the byte-buffer to account for
        }
        else if (reader.CurrentEncoding.CodePage == 1200) // UTF-16LE
        {
            if (byteBuffer[byteLen - 1] >= 0xd8) // high-surrogate
                numFragments = 2; // account for the partial character
        }
        else if (reader.CurrentEncoding.CodePage == 1201) // UTF-16BE
        {
            if (byteBuffer[byteLen - 2] >= 0xd8) // high-surrogate
                numFragments = 2; // account for the partial character
        }
    }
    return reader.BaseStream.Position - numBytesLeft - numFragments;
}

Конечно, это использует Reflection для получения частных переменных, поэтому есть риск. Однако этот метод работает с .Net 2.0, 3.0, 3.5, 4.0, 4.0.3, 4.5, 4.5.1, 4.5.2, 4.6 и 4.6.1. Помимо этого риска единственным критическим предположением является то, что базовый байт-буфер является byte[1024]; если Microsoft изменяет его неправильно, метод прерывается для UTF-16/-32.

Это было протестировано против файла UTF-8, заполненного Ažテ? (10 bytes: 0x41 C5 BE E3 83 86 F0 A3 98 BA), и файла UTF-16, заполненного A? (6 bytes: 0x41 00 01 D8 37 DC). Суть заключается в том, чтобы заставить фрагмент символов вдоль границ byte[1024], все различные способы, которыми они могли бы быть.

UPDATE (2013-07-03). Я исправил метод, изначально используемый сломанным кодом из этого другого ответа. Эта версия была протестирована против данных, содержащих символы, требующие использования суррогатных пар. Данные были помещены в 3 файла, каждый с другой кодировкой; один UTF-8, один UTF-16LE и один UTF-16BE.

UPDATE (2016-02). Единственный правильный способ обработки двухпользовательских символов — прямо интерпретировать базовые байты. UTF-8 правильно обрабатывается, а работа UTF-16/-32 (с учетом длины byteBuffer).

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