https://habrahabr.ru/post/280714/- Занимательные задачки
- Python
Это статья про довольно неожиданный результат выполнения программы на python. Матёрым разработчикам она покажется детским лепетом, но для тех, кто изредка использует python как полезный инструмент будет несомненно интересна. Также рекомендую её как гимнастику ума. Чтобы заняться этой гимнастикой могли все желающие не добавлял в статью ни строчки кода.
Недавно мне потребовалось автоматизировать довольно сложный процесс раскладки файлов по каталогам. Опыта в этом у меня довольно немного, но всё шло хорошо. Я написал несколько скриптов bash, которые занимались сжатием/распаковкой и переименовыванием/перемещением файлов, но тут потребовалось получать данные для некоторых операций из текстового файла.
Конкретно задача выглядела так:
1) Взять первую строку файла name.txt, оканчивающуюся подстрокой |some_data
2) Вычленить из неё подстроку some_data
3) Сжать name.txt в архив some_data.zip
Незадолго до этого коллега любезно написал мне программу на Python, реализующую схожий функционал — копирование, с некоторыми условиями, первых строк всех файлов из каталога в один. Я решил слегка подправить эту программу под текущую задачу.
Код, как и обещал, не привожу, только алгоритм. Сразу скажу, что выполняется он абсолютно правильно, именно так, как я и описываю, без ошибок или неточностей.
Алгоритм:
1) Взять первую строку файла name.txt
2) Вычленить из неё всё, после символа '|' и записать в переменную s
3) Удалить из s все переносы строки (символ '\n')
4) Удалить из s все пробелы
5) Если s — пустая строка ('') вывести об этом сообщение и закончить программу
6) Добавить в конец переменной s символы '.zip'
7) Выполнить в консоли «zip [вставить значение s] name.txt»
При выполнении у меня случился экзистенциальный кризис. Программа не создавала файлы вида abcdef.zip, она создавала файлы вида .zipef. То есть вместо добавления .zip к переменной s она выводила '.zip' вместо первых четырёх символов.
Иначе говоря, получалось, что для python 'abcde' + 'fgh' == 'fghde'. Проблема усугублялась тем, что до этого я с python вообще никак не сталкивался и не был уверен, что подобное поведение не норма. В самом деле, берём адрес массива, пишем по этому адресу другой массив и считываем — получили второй массив поверх первого.
К счастью оказалось что это не так и строки должны нормально конкатенироваться.
Для устранения этой проблемы мне потребовалось около часа. Все необходимые данные у вас есть, попробуйте предположить причину этого безобразия.
А дело вот в чём1) Взять первую строку файла name.txt
2) Вычленить из неё всё, после символа '|' и записать в переменную s
3) Удалить из s все переносы строки (символ '\n')
Кое-что критично важное мы не удалили. Символ '\r' — возврат каретки. В итоге происходит вот что:
Пусть s == «abcdef\r». Мы добавили в конец '.zip' и получили «abcdef\r.zip».
Обозначим знаком _ курсор; рассмотрим три этапа вывода строки s:
//выводим 'abcdef'
>abcdef_
//выводим '\r'- курсор переводится
>_abcdef
//печатаем '.zip'
>.zip_ef
Рекомендую в схожих ситуациях проверять вообще все
управляющие символы, поскольку создавать файлы с именами типа «File <табуляция>Name» тоже не очень хорошо.