Книга: Linux программирование в примерах
13.2.6. Пример: форматирование числовых значений в gawk
13.2.6. Пример: форматирование числовых значений в gawk
реализует свои собственные версии функций
gawkprintf()
и sprintf()
. Для полного использования локали gawk
должен поддерживать флаг '
, как в С. Следующий фрагмент из файла builtin.c
в gawk
3.1.4 показывает, как gawk
использует struct lconv
для числового форматирования:
1 case 'd':
2 case 'i':
3 ...
4 tmpval = force_number(arg);
5
6 ...
7 uval = (uintmax_t)tmpval;
8 ...
9 ii = jj = 0;
10 do {
11 *--cp = (char)('0' + uval % 10);
12 #ifdef HAVE_LOCALE_H
13 if (quote_flag && loc.grouping[ii] && ++jj == loc.grouping[ii]) {
14 *--cp = loc.thousands_sep[0]; /* XXX - предположение, что это один символ */
15 if (loc.grouping[ii+1] == 0)
16 jj = 0; /* продолжить использовать текущий val в loc.grouping [ii] */
17 else if (loc.grouping[ii+1] == CHAR_MAX)
18 quote_flag = FALSE;
19 else {
20 ii++;
21 jj = 0;
22 }
23 }
24 #endif
25 uval /= 10;
26 } while (uval > 0);
(Номера строк даны относительно начала фрагмента.) Некоторые части кода, не имеющие отношения к обсуждению, были опущены, чтобы облегчить фокусировку на важных частях.
Переменная loc
, используемая в строках 13–17, представляет struct lconv
. Она инициализируется в main()
. Здесь для нас интерес представляет loc.thousands_sep
, который является символом разделителя тысяч, и loc.grouping
, который является массивом, описывающим число цифр между разделителями. Нулевой элемент означает «использовать для всех последующих цифр значение предыдущего элемента», а значение CHAR_MAX
означает «прекратить вставку разделителей тысяч».
С таким введением, давайте посмотрим на код. Строка 7 устанавливает uval
, которая является беззнаковой версией форматируемого значения. ii
и jj
отслеживают положение в loc.grouping
и число цифр в текущей группе, которые были преобразованы, соответственно[142]. quote_flag
равен true, когда в спецификации преобразования был отмечен символ '
.
Цикл do-while
генерирует символы цифр в обратном порядке, заполняя буфер с конца к началу. Каждая цифра создается в строке 11. Затем строка 25 делится на 10 путем смещения значения вправо на одну десятичную цифру.
Нас интересуют строки 12–24. Эта работа осуществляется только на системе, поддерживающей локали, на что указывает наличие заголовочного файла <locale.h>
. Именованная константа HAVE_LOCALE
в такой системе будет равна true[143].
Когда условие в строке 13 истинно, настало время добавить символ разделителя тысяч. Это условие можно прочесть как «если требуется группировка и текущее положение в loc.grouping
указывает нужное для группировки количество и текущее число цифр равно группируемому количеству». Если это условие истинно, строка 14 добавляет символ разделителя тысяч. Комментарий обращает внимание на предположение, которое, вероятно, истинно, но которое может вновь появиться позже. ('XXX' является традиционным способом выделения опасного или сомнительного кода. Его легко отыскать, и он весьма заметен для читателя кода.)
После использования текущего положения в loc.grouping
строки 15–22 заглядывают в значение в следующем положении. Если это 0, продолжает использоваться значение текущего положения. Мы указываем на это, восстанавливая 0 в jj
(строка 16). С другой стороны, если в следующем положении CHAR_MAX
, группировка должна быть прекращена, и строка 18 убирает ее, устанавливая quote_flag
в false. В противном случае, следующее значение является значением группировки, поэтому строка 20 восстанавливает 0 в jj
, а строка 21 увеличивает значение ii
.
Это низкоуровневый, подробный код. Однако, поняв один раз, как представляется информация в struct lconv
, код читать просто (и его было просто писать).
- 13.2.1. Категории локалей и переменные окружения
- 13.2.2. Установка локали: setlocale()
- 13.2.3. Сравнение строк: strcoll() и strxfrm()
- 13.2.4. Числовое и денежное низкоуровневое форматирование: localeconv()
- 13.2.5. Высокоуровневое числовое и денежное форматирование: strfmon() и printf()
- 13.2.6. Пример: форматирование числовых значений в gawk
- 13.2.7. Форматирование значений даты и времени: ctime() и strftime()
- 13.2.8. Другие данные локали: nl_langinfo()
- Множественное присвоение значений:
- Пример установочного скрипта
- Пример из практики
- ПРИМЕР ПРОСТОЙ ПРОГРАММЫ НА ЯЗЫКЕ СИ
- Примеры получения статистики
- Пример применения метода «пять почему»
- Определение пользовательского формата числовых данных
- Пример 12-8. Частота встречаемости отдельных слов
- 1.2.5. Пример программы
- Пример 17-10. Блочный комментарий
- Примеры
- 2. Пример создания базового отношения в записи на псевдокоде