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

Однако программное обеспечение — это не только проекты компьютерных игр класса ААА или корпоративных проектов, предлагающих программное обеспечение по модели SaaS, это и использование его в обычной жизни, порой весьма неожиданным образом. О чём мы и поговорим в этой статье.

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

Компания, в которой я одно время работал, представляла собой достаточно большой и старый холдинг, с множеством офисов по всему миру. Из головного офиса, который находился в Москве, периодически было необходимо рассылать списки рабочих файлов, переименованных с учётом местной специфики и языка. То есть мы имеем достаточно большое количество файлов, которые должны быть названы с использованием терминов языка той страны, куда они посылаются.

Казалось бы, достаточно простая задача, и если она решается в рамках компании, спецификой которой является отсылка подобного — логично предположить, что компания тем или иным способом сможет решить эту проблему. Но это только в теории! В реальной жизни эта проблема никак не была решена, и после того, как корректные названия (в виде списка файлов) были составлены переводчиком, сотрудники тратили достаточно большое количество рабочего времени на их переименование.

Проблема усугублялась ещё и тем, что списки файлов были большими: от 100 штук и более. Ну и конечно, не забываем тот факт, что в любой крупной компании, в которой работа протекает в достаточно интенсивном режиме, любая задача должна быть «выполнена ещё позавчера». То есть время всегда критично.

Совершенно случайно эта проблема стала известна мне, и я решил поспособствовать её решению (забегая вперёд, скажу, что никаких позитивных «плюшек» мне за это не прилетело, ну да и ладно).

То есть, если попытаться как-то формализовать стоящую задачу, её можно выразить в виде 3 пунктов:

  1. Нужно создать список файлов, которые подлежат переименованию.
  2. Нужно создать список будущих названий файлов.
  3. Переименовать файлы согласно списку из пункта 2 и сохранить в новое место.

Так уж сложилось, что я знаю язык программирования java и потому решил писать скрипт именно на нём.

Согласно первому пункту, нам необходимо сначала раздобыть этот список файлов, предварительно положенных в какую-либо папку. Это можно сделать программным способом, то есть написать небольшой скриптик самому, однако мне это было лень делать, так как на моём компьютере уже был установлен Total Commander, у которого есть встроенная функция вывода списка файлов из определённой директории.

Именно им я и воспользовался и вставил этот список в Microsoft Word, после чего сохранил как файл с расширением txt.

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

Полученный от переводчика список, где каждое название находилось в отдельной строке, я также сохранил прямо из ворда, в файл с расширением .txt ( изначально переводчик передал файл со списком в формате Microsoft Word).

Ну и на последнем этапе нам надо будет указать нашему скрипту директорию, куда необходимо писать переименованные файлы. Рекомендуется создать копию изначальных файлов, так как скрипт делает «вырезать-переименовать-вставить». Поэтому лучше изначальные файлы сохранить для возможности переименования на другие языки.

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

Сначала создадим 3 потока, каждый из которых будет читать из консоли среды разработки IntelliJ IDEA.

Первый из которых будет читать список файлов, второй — будет читать список, где лежат названия на национальных языках, а третий поток — читает директорию, куда будут писаться переименованные файлы. Таким образом, мы имеем гибкое решение: нам для каждого переименования на новый язык нужно всего лишь «скормить» скрипту 3 места, и дальше он всё сделает сам:

BufferedReader bufferedReader1 = new BufferedReader((new InputStreamReader(System.in)));

BufferedReader bufferedReader2 = new BufferedReader((new InputStreamReader(System.in)));

BufferedReader bufferedReader3 = new BufferedReader((new InputStreamReader(System.in))); 

Создадим три строки, куда будет писаться прочитанное:

String files = bufferedReader1.readLine();

String names = bufferedReader2.readLine();

String destination_place = bufferedReader3.readLine();

Затем освобождаем ресурсы:

bufferedReader1.close();

bufferedReader2.close();

bufferedReader3.close();

Далее нам нужно считать все файлы, необходимые для переименования, и сохранить их в массив:

BufferedReader namesReader = new BufferedReader(new FileReader(names));

File[] filesList;

File filesPath = new File(files);

// создаём объект на папку с файлами

filesList = filesPath.listFiles();

// записываем файлы из папки в массив объектов типа File

    	String stringBuilder = null;

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

// читаем по одной строке из файла и затем переименовываем файлы на жёстком диске

while (namesReader.ready())

    	{

      	for(int i=0; i<filesList.length; i++)

        	{

            	// читаем название из списка

            	String s = namesReader.readLine();

            	stringBuilder = destination_place + "\\" +  s + ".jpg" ;

// читаем текущее имя файла, переименовываем и записываем

            	filesList[i].renameTo(new java.io.File(stringBuilder));  

        	}

    	}

    	namesReader.close();

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

import java.io.*;

import java.io.File;

public class Renamer {

public static void main(String [] args) throws IOException {

BufferedReader bufferedReader1 = new BufferedReader((new InputStreamReader(System.in)));

// читаем из консоли, где лежит список файлов для переименования

BufferedReader bufferedReader2 = new BufferedReader((new InputStreamReader(System.in)));

// читаем из консоли, где лежит список будущих названий

BufferedReader bufferedReader3 = new BufferedReader((new InputStreamReader(System.in)));

// читаем из консоли, куда писать переименованные файлы

    	String files = bufferedReader1.readLine();

    	String names = bufferedReader2.readLine();

    	String destination_place = bufferedReader3.readLine();

    	bufferedReader1.close();

    	bufferedReader2.close();

    	bufferedReader3.close();

    	BufferedReader namesReader = new BufferedReader(new FileReader(names));

    	File[] filesList;

// создаём объект на папку с файлами

    	File filesPath = new File(files);

// записываем файлы из папки в массив объектов типа File

    	filesList = filesPath.listFiles();

    	String stringBuilder = null;

// читаем по одной строке из файла и затем переименовываем файлы на жёстком диске

    	while (namesReader.ready())

    	{

        	for(int i=0; i<filesList.length; i++)

        	{

// читаем название из списка

            	String s = namesReader.readLine();

            	stringBuilder = destination_place + "\\" +  s + ".jpg" ;

// читаем текущее имя файла, переименовываем и записываем

            	filesList[i].renameTo(new java.io.File(stringBuilder));  

        	}

    	}

    	namesReader.close();

	}


В примере выше рассмотрено переименование типа файлов с расширением .jpg, но это могут быть файлы любого формата: презентации, файлы Ворд, чертежи и т.д. и т.п.

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

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

Суть проблемы: департамент маркетинга с некой периодичностью выпускает каталог продукции, который является многостраничным документом и содержит большое количество страниц. В среднем количество страниц колеблется от 300 до 500.

Особенность вёрстки такого рода каталога заключается в том, что он собирается с использованием полиграфической программы Adobe Indesign, где для устранения возможности «съезжания» выверенного текста со страниц (с которыми работа закончена) — применяется своеобразный подход. Каждая страница в каталоге оторвана от каждой последующей и предыдущей!

То есть что это значит: если сравнивать с документом Microsoft Word, когда вы добавляете некие страницы впереди документа, весь текст, который находится ниже, автоматически перетекает на следующую страницу, освобождая место впереди для вашего нового текста. Всё оформление ниже подстраивается соответственно, автоматически.

При использовании подхода, когда каждая страница «оторвана» от предыдущей (текст на неё не может перетекать), возникает проблема: так как каждая страница имеет оформление, которое имеет либо правую, либо левую ориентацию, то ввиду специфических свойств Adobe Indesign это оформление автоматически не назначается для находящихся ниже страниц. То есть, другими словами, когда мы впереди добавили нечётное количество страниц и страницы находящиеся ниже этого места поменяли свою ориентацию (левые стали правыми и наоборот), нам необходимо исправить получившееся.

Как должно быть:



Как стало:



Такого рода исправления в Adobe indesign осуществляются применением правых или левых шаблонов оформления соответственно — к правой и левой странице. Шаблоны можно применять к интервалу страниц. То есть, например, можно применить левый шаблон к чётным страницам в интервале с 1 по 500 страницу, а правый шаблон (который находится на развороте справа) — к нечётным страницам в интервале с 1 страницы по 500.

Таким образом, если ещё больше специализировать задачу, получается, что нам необходимо вывести чётные числа в диапазоне от 1 до 500 и также нечётные числа в диапазоне от 1 до 500. Любой программист скажет, что это одна из самых «плёвых» задач.

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

В нашем же случае мы также применим язык программирования Java и напишем небольшой скриптик:

import java.io.*;

public class Solution {

	public static void main(String [] args) throws IOException {

    	int j = 100; // диапазон страниц

    	int flag = 1; //флаг: для нечётных ставить 1;

               	// для чётных - 2;

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

        	{

             	// для вывода чётных номеров страниц

             	if (flag==2)

             	{

                 	if (i%2==0)

                 	{

                     	if ((i<j)&&(i!=0))

                     	{

                         	System.out.print(i + ",");

                     	}

                     	else if (i!=0)

                     	{

                         	System.out.print(i);

                     	}

                 	}

             	}

             	// для вывода нечётных номеров страниц

             	else if (flag==1)

             	{

                 	if (i%2!=0)

                 	{

                     	if (i<j-1)

                     	{

                         	System.out.print(i + ",");

                     	}

                     	else

                     	{

                         	System.out.print(i);

                     	}

                 	}

             	}

        	}

	}

}

Скрипт достаточно лаконичный и при установке флага под названием int flag позволяет легко выводить нужный диапазон страниц. Чётных или нечётных соответственно.

Вывод программы для нечётных чисел в диапазоне от 1 до 100:



Вывод программы для чётных чисел в диапазоне от 1 до 100:



И теперь нам остаётся только скопировать полученный диапазон из вывода программы в IntelliJ IDEA и вставить в Adobe Indesign (для чётных и нечётных страниц разные диапазоны). Ниже показан пример применения к нечётным страницам из диапазона от 1 до 100:



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

Если вам приходилось решать подобные задачи, напишите об этом в комментариях. Нам будет очень интересно узнать о вашем опыте!


НЛО прилетело и оставило здесь промокоды для читателей нашего блога:

15% на все тарифы VDS (кроме тарифа Прогрев) — HABRFIRSTVDS.

20% на выделенные серверы AMD Ryzen и Intel Core HABRFIRSTDEDIC.

Комментарии (12)


  1. gatoazul
    10.01.2022 11:05

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


    1. kot_review Автор
      11.01.2022 13:43

      Именно так и было сделано. Просто тут вопрос в том, что перетекание (когда оно есть) — оно автоматом решает вопрос правых и левых страниц. Правда перетекание обычно приводит к не прогнозируемым ошибкам и потребности правок «ниже этого места». Что в условиях катастрофической нехватки времени – весьма критично. А когда выключено – приходится потом применять шаблон к диапазону страниц, что и было показано ;-).


  1. gdt
    10.01.2022 19:10
    +1

    А что, разве в java нет метода наподобие copyTo()? Ну чтобы не заморачиваться с восстановлением исходных файлов, если вдруг языков оказалось больше одного.

    Также интересно, неужели одного ридера недостаточно, чтобы последовательно считать три строки? Что, если строк тысячи? И если уж на то пошло, ридер != поток, поток это как раз in должен быть в данной ситуации, и вы его не создаете, т к он дан нам в ощущениях так сказать :)

    Во втором скрипте, судя по всему, цикл можно начинать с единицы — минус условие. Далее флаг и количество страниц можно получать из параметров командной строки (или считывать с консоли) — если утилита нужна часто, каждый раз пересобирать может быть неоправданно. Скорее всего вышло бы лаконичнее, если вынести создание коллекции чисел в отдельный метод, принимающий количество и флаг, а в main применить какой-нибудь string join (не знаю, как в java называется) — который сам бы и расставил запятые где нужно.


    1. kot_review Автор
      11.01.2022 13:44

      Согласен, совершенство не знает границ — любую задачу можно решить многими способами ;-) Но сами скрипты вполне себе сработали в той ситуации, когда необходимо было срочно оптимизировать работу в этой области и выполнили свою роль. Соответственно, оптимизировать их конечно можно и нужно, но по большому счету, только из-за «любви к искусству».


  1. dimaaannn
    10.01.2022 20:50
    +6

    Чёт какая то хрень.

    Банальная бытовая автоматизация. И это без учёта того, что в индизайне тоже можно писать скрипты автозамены и автоматизировать вёрстку.


    1. TimsTims
      11.01.2022 10:43
      +5

      Ага. "Я знаю Java, поэтому список файлов я буду получать из Total Commander."


    1. kot_review Автор
      11.01.2022 13:45

      Банальная бытовая автоматизация. И это без учёта того, что в индизайне тоже можно писать скрипты автозамены и автоматизировать вёрстку.
      Верно, именно в этом и была цель статьи, — показать, как может быть применено программирование для сферы, вообще далекой от этого. То есть, рассказать на своём примере, как даже обычные простые (казалось бы) вещи могут оказаться вполне себе сложными, если их решать иначе. И наоборот – как программное обеспечение может существенно облегчить жизнь, даже если его применять «точечно и совсем не в этой сфере» :-)

      P.S. насколько мне известно (могу и ошибаться) – скрипты для индизайна пишутся на javascript – а я с ним не очень хорошо дружу. Ну так уж вышло :-)


  1. alex_shpak
    11.01.2022 00:18
    +2

    Спасибо за интересную статью!

    Слышал, в Total Commander'е в Multi-Rename Tool есть функция "загрузить имена файлов из текстового файла", но сам не пользовался - не приходилось. Вы её не рассматривали или она Вам по каким-то причинам не подошла?

    По поводу второй программы - больше всего повезло линуксоидам, у них для этого уже есть команда seq :) Но нет Adobe Indesign :(

    Если вам приходилось решать подобные задачи

    Скрипт для проверки обновлений на сайтах:

    w3m $url >$file.new
    diff $file.old $file.new
    mv $file.new $file.old

    Запущенный с аргументами $file и $url, следит не изменилась ли информация по данному адресу. Если добавить в cron - получаем ежедневную проверку и оповещение на email об изменениях.

    Ещё был поиск и перекодирование всех найденных файлов *.wav в *.mp3 - код приводить не буду, но там последовательность find, xargs, и ffmpeg :)


  1. RiverFlow
    11.01.2022 11:10
    +1

    Знал бы автор ещё и джаваскрипт не было бы статьи...


    1. vassabi
      11.01.2022 12:17

      или python, или любой шелл (хоть виндовый хоть юниксовый)


      1. unsignedchar
        11.01.2022 12:32

        Была бы такая же статья, но про python/bash/макросы excel/… ;)


  1. tzlom
    11.01.2022 14:29
    -2

    обе задачи можно сделать нагуглив соответствующий веб сервис быстрее чем откроется IDE