Форматированный вывод
Подавляющее большинство мануалов по тем или иным языкам программирования показывают прекрасный пример того, как начинающему программисту написать свой первый "Hello, world!" и это прекрасно! Давайте разбираться, почему этого недостаточно и как сделать жизнь программиста чуть лучше. Да, по форматированному выводу написано также огромное количество мануалов, в том числе в стандартных документациях к языкам, но почему бы не сделать попытку отказаться от казённого языка больших компаний и не рассказать своими словами?
Немного истории
Современные языки программирования, так или иначе, но берут своё начало в C.
...
...
...
Так, мы подождали, когда нас покинут эксперты в области истории программирования и можем спокойно продолжать. Подавляющее большинство так называемых "языков высокого уровня" содержат отличную стандартную библиотеку функций (классов и методов), в которой описана функция print()
она обычно либо лежит в системном классе, либо в другом очень удобном и доступном месте. Все люди ей радостно пользуются, и если нужно, например, собрать строчку из нескольких составляющих просто применяют конкатенацию строк, получая что-то вроде print("Hello, I'm " + "Ivan " + 35 + " years of age");
. Всё очень хорошо и понятно. но можно лучше. Разработчики языков программирования придумали, как избавиться от конкатенации и удобно форматировать строки. Нужно написать параметризированный шаблон и подставлять в него значения. Всего навсего.
Понятие форматирования
Всё началось в K&R C, где функция print();
не была описана вовсе. Это было для меня камнем преткновения изучения C в школе, где на уроках информатики нам преподавали QBasic. Я использовал директиву print();
а компилятор упорно утверждал, что не знает такой. Удивительно, что простой вывод осуществлялся функцией printf();
что расшифровывалось как print formatted. Форматированный вывод подразумевал как раз создание шаблона строки и заполнения его параметрами, хотя и простой "Hello, world" с его помощью вывести можно. Что представляет собой форматирование? Это отличается от того, к чему мы привыкли при форматировании текста в HTML или MS Word, где под этим словом подразумевается создание отступов, интервалов и прочих украшательств. В программировании форматирование - это создание таких мест в строке, которые будут заполнены значениями, так или иначе переданными шаблону. Места, которые будут заполнены значениями отмечаются в шаблоне специальной последовательностью, которая называется placeholder (англ. - держатель места, заполнитель). То есть, если мы опишем вызов шаблона "Hello, %s"
и передадим в него литерал "world"
вся строка в шаблоне выведется "как есть", а заполнитель заменится на переданный литерал. Заполнитель представляет собой символ %
и некоторую последовательность, означающую, собственно, формат принимаемого в заполнитель значения. Самые популярные заполнители - это:
- %s
- string, обычный строковый литерал. Представляется "как есть", не дополняется никакими символами и не обрезается.
- %d
, %i
- decimal, integer - целое число в десятичной системе счисления. Разницы в использовании %d
и %i
нет
- %x
, %X
- hexadecimal - целое число в шестнадцатиричном представлении. Разница между %x
и %X
в том, что в итоговой строке будут использованы строчные или заглавные буквы A-F для представления чисел 10-15
- %f
- float - числа с плавающей точкой (дробные числа)
- %c
- character - символ.
- %%
- собственно, символ процента. Поскольку с него начинается специальная последовательность, чтобы вывести символ "как есть" нужно было положить его внутрь последовательности. Выкрутились.
Параметры, передаваемые заполнителям, передаются в ту же функцию форматирования после строки шаблона через запятую (функции форматирования всегда принимают аргумент переменной длины). Параметры всегда присваиваются заполнителям в том порядке, в котором переданы, то есть первый заполнитель всегда держит место для первого параметра, второй для второго и так далее.
Некоторые заполнители могут дополняться параметрами, так, например, %5d
будет означать, что переданное целое число будет помещено в пространство из не менее, чем пяти символов (слева будут дописаны пробелы, если число занимает меньше символов). Используя же %05d
мы будем минимальное выделенное пространство заполнять не пробелами, а нулями. Или, к примеру, в случае %.2f
мы указываем, что дробную часть числа при отображении следует обрезать до двух символов, и число 1.23456 будет отображено как 1.23.
C/C++
Функция printf();
это весьма удобная альтернатива простому выводу в поток вывода в C++. Оператор std::cout
не предоставляет возможности к форматированию строк и поэтому, несмотря на свою популярность, не может считаться равноценной заменой классическому printf();
Более того в языке присутствует функция sprintf();
позволяющая осуществлять форматированный вывод не в консоль, но в другой строковый литерал.
char fmt[20]; sprintf(fmt, "shift |%%%dd|, 7); // no output, but fmt == "shift |%7d|" printf(fmt, 10); printf("preformatted with zeros %07d", 10); // shift | 10| // preformatted with zeros 0000010
Java
В Java классические форматтеры представлены методами System.out.printf();
(а если быть совсем точным, то PrintStream#printf();
) и String#format();
первый осуществляет вывод форматированной строки в поток, второй в строку.
System.out.printf("%s loves string formatting\n", "Everyone"); System.out.println(String.format("Sadly, %.2f%% of programmers use it", 50f)); // Everyone loves string formatting // Sadly, 50.00% of programmers use it
Python
Здесь форматирование осуществляется всегда для строки и может использоваться внутри функции print()
, например, для заполнения значением конкретной переменной
customstring = "String formatting" print(f"{customstring} is powerful") # String formatting is powerful
или близким к классическому способом
print("Machine learning provides {} the ability to learn {}".format("systems", "automatically")) # Machine learning provides systems the ability to learn automatically
Вообще, python в части форматирования строк "пошёл" дальше всех, потому что предоставляет механизмы для именованного заполнения, повторного заполнения держателей и использования.
print("{2} has a friend called {0} and a sister called {1}". format("Betty", "Linda", "Daisy")) # Daisy has a friend called Betty and a sister called Linda tool="Unsupervised algorithms" goal="patterns" print("{title} try to find {aim} in the dataset".format(title=tool, aim=goal)) # Unsupervised algorithms try to find patterns in the dataset
Выводы
Естественно, каждый может найти как десяток доводов продолжать использовать форматирование строк, так и десяток доводов продолжать их не использовать. В этой статье я постарался ответить на вопрос "а что это у Вас за странный вызов на печать такой", а не дать читателю завет "всегда пользуйся только вот этим". Поиск доводов "за" и "против" автор всегда оставляет читателю.