Язык Си в примерах/Верхний регистр

Язык Си в примерах


  1. Компиляция программ
  2. Простейшая программа «Hello World»
  3. Учимся складывать
  4. Максимум
  5. Таблица умножения
  6. ASCII-коды символов
  7. Скобочки
  8. Факториал
  9. Степень числа
  10. Треугольник Паскаля
  11. Корень уравнения
  12. Система счисления
  13. Сортировка
  14. Библиотека complex
  15. Сортировка на основе qsort
  16. RPN-калькулятор
  17. RPN-калькулятор на Bison
  18. Простая грамматика
  19. Задача «Расчёт сопротивления схемы»
  20. Простая реализация конечного автомата
  21. Использование аргументов командной строки
  22. Чтение и печать без использования stdio
  23. Декодирование звукозаписи в формате ADX
  24. Другие примеры
  25. XCC C
Дано
текст — последовательность кодов ASCII — на стандартном вводе программы. Последовательность конечна, но ее длина заранее неизвестна.
Надо
вывести на стандартный вывод исходный текст, заменив в нем строчные буквы латиницы (a, …, z) прописными (A, …, Z).
Указание
воспользоваться особенностью кодовой таблицы ASCII: коды прописных букв отличаются от кодов соответствующих строчных на постоянную величину (а именно: 32.)
Дополнительно
предполагая поддержку средой русскоязычной локали, реализуйте аналогичное преобразование для кириллических текстов (используя стандартные функции языка.)

Решение

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

Обратите внимание на то, что с символами (переменными типа char) можно оперировать как с числами. В частности, 'Z' - 'A' есть число, равное разности кодов символов A и Z, то есть (при использовании кодовой таблицы ASCII) 25 — число букв в латинском алфавите минус 1. Символы можно также сравнивать друг с другом, при этом сравниваются их коды.

#include <assert.h>
#include <stdio.h>

int
main ()
{
  int c;
  while ((c = getchar ()) != EOF) {
    if ('a' <= c && c <= 'z') {
      c += 'A' - 'a';
    }
    putchar (c);
  }
  assert (! ferror (stdin));

  return 0;
}

Главный циклусловие корректности ввода) этой программы почти полностью совпадают с рассмотренными в разделе ASCII коды символов. Однако, вместо использования printf для вывода значений считанных кодов, здесь мы используем функцию putchar для вывода самих кодов (знаков), возможно — после преобразования.[1] В коде по-прежнему используются функции getchar и ferror.[2][3]

Обратите внимание, что сформировать условие «конец потока» при вводе с клавиатуры можно вводом (в зависимости от системы и предполагая настройки по-умолчанию) Control-d или Control-z (также обозначаются C-d, ^D, C-z, ^Z.)

Использование стандартной библиотеки

Приведенный выше код можно еще более упростить, если воспользоваться стандартной функцией преобразования регистра toupper, объявленной в заголовке ctype.h.[4]

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

#include <assert.h>
#include <ctype.h>
#include <stdio.h>

int
main ()
{
  int c;
  while ((c = getchar ()) != EOF) {
    putchar (toupper (c));
  }
  assert (! ferror (stdin));

  return 0;
}

Кроме латиницы

Стандарт предусматривает также ряд средств для поддержки письменностей, отличных от «базовой» (26-символьной) латиницы. В основе такой поддержки — два следующих понятия:

  1. локаль — набор сведений о письменности, языке и культуре, включающий, помимо прочего, таблицы соответствия символов верхнего и нижнего регистров;
  2. широкие символьные типы (wchar_t, wint_t; англ. wide character) — для представления ряда письменностей (например — основанных на иероглифах), а равно для представления текстов на нескольких языках, «байтового» типа char оказывается недостаточно; как следствие, в задачах, связанных с обработкой многоязычных текстов, его заменяет тип wchar_t; аналогично, в операциях ввода-вывода используется тип wint_t (и константа WEOF.)

Соответственно, в исходный вариант вносятся следующие изменения.

  1. Появляется вызов setlocale (LC_ALL, ""), инициализирующий локаль в соответствии с текущими настройками. (По-умолчанию, при запуске программы полагается setlocale (LC_ALL, "C") — установка «стандартной» локали.)[5]
  2. Функции getwchar, towupper, putwchar заменяют соответствующие для «узких» символов (getchar, toupper, putchar.) Соответственно меняются тип (intwint_t) и константа признака исчерпания входного потока (EOFWEOF.)[6][7][8]
  3. Включаются соответствующие заголовки (locale.h, wchar.h, wctype.h.)

#include <assert.h>
#include <locale.h>
#include <stdio.h>
#include <wchar.h>
#include <wctype.h>

int
main ()
{
  char *rl
    = setlocale (LC_ALL, "");
  assert (rl != 0);

  wint_t c;
  while ((c = getwchar ()) != WEOF) {
    putwchar (towupper (c));
  }
  assert (! ferror (stdin));

  return 0;
}

Отметим, впрочем, что принятые в конкретном языке правила обращения со строчными и заглавными могут оказаться сложнее простой зависимости символ—символ, предполагаемой в данном примере. Так, например, правила немецкого языка ставят в соответствие строчной «ß» пару заглавных — «SS» (например: Straße → STRASSE), что ни коим образом не может быть реализовано функцией towupper.

Задания

  1. Проверьте работу программы вводом строк Hello! и Привет!. Удостоверьтесь, что «базовые» варианты решения выполняют заданное преобразование лишь для первой из них, в то время как «интернационализованное» решение действует и в отношении кириллического ввода.
  2. Разработайте варианты программы, выполняющие (вновь для латиницы) a. преобразование верхнего регистра в нижний и b. «переключение» регистра — Hello!hELLO!. (Указание: воспользуйтесь стандартными функциями islower и isupper.[9][10])

См. также

Примечания

  1. 7.21.7.8 The putchar function (англ.). WG14 N1570 Committee Draft. ISO/IEC (12 апреля 2011). Дата обращения: 19 ноября 2012.
  2. 7.21.7.6 The getchar function (англ.). WG14 N1570 Committee Draft. ISO/IEC (12 апреля 2011). Дата обращения: 19 ноября 2012.
  3. 7.21.10.3 The ferror function (англ.). WG14 N1570 Committee Draft. ISO/IEC (12 апреля 2011). Дата обращения: 19 ноября 2012.
  4. 7.4.2 Character case mapping functions (англ.). WG14 N1570 Committee Draft. ISO/IEC (12 апреля 2011). Дата обращения: 19 ноября 2012.
  5. 7.11.1.1 The setlocale function (англ.). WG14 N1570 Committee Draft. ISO/IEC (12 апреля 2011). Дата обращения: 19 ноября 2012.
  6. 7.29.3.7 The getwchar function (англ.). WG14 N1570 Committee Draft. ISO/IEC (12 апреля 2011). Дата обращения: 19 ноября 2012.
  7. 7.30.3.1.2 The towupper function (англ.). WG14 N1570 Committee Draft. ISO/IEC (12 апреля 2011). Дата обращения: 19 ноября 2012.
  8. 7.29.3.9 The putwchar function (англ.). WG14 N1570 Committee Draft. ISO/IEC (12 апреля 2011). Дата обращения: 19 ноября 2012.
  9. 7.4.1.7 The islower function (англ.). WG14 N1570 Committee Draft. ISO/IEC (12 апреля 2011). Дата обращения: 19 ноября 2012.
  10. 7.4.1.11 The isupper function (англ.). WG14 N1570 Committee Draft. ISO/IEC (12 апреля 2011). Дата обращения: 19 ноября 2012.