результат форматирования схемы gimp с начальными нулями

#scheme #gimp #script-fu

#схема #gimp #сценарий-fu

Вопрос:

Я пытаюсь получить временную метку для имени файла. Я использую процедуру (время), которая дает текущую временную метку:

 (120 11 29 17 32 25)
 

год-1900 месяц-1 день час минута секунда

 (  1900 (car (time)) )(  1 (cadr (time)))(caddr(time))(cadddr(time))(cadr(cdddr(time)))(caddr(cdddr(time)))
 

это почти хорошо, но … если какой-либо из элементов меньше 10 (например, первого января около 1 часа ночи).:

 (121 0 1 1 2 3)
 

это дает неверную временную метку, потому что мне нужны начальные нули

202111123 должно быть 20210101010203

Интересно, есть ли более простой метод, чем проверка длины элемента и добавление «0»

Ответ №1:

Script-Fu основан на Tiny Scheme, которая сама по себе является подмножеством схемы R5RS. В схеме R5RS нет встроенной функции для форматирования чисел или строк, подобных этому, и, насколько я знаю, в Script-Fu ничего не добавлено, поэтому вам нужно будет создать для этого свои собственные функции.

Было бы проще всего работать со строками, и вам, вероятно, все равно нужны строки для добавления метки времени к имени файла.

Вот функция, которая дополняет строку нулями. Обратите внимание, что результат имеет длину не менее width символов, но входные str данные не обрезаются, если они уже длиннее, чем width :

 (define (left-pad str width pad)
  (let add-padding ((s str))
    (if (< (- width (string-length s)) 1)
        s
        (add-padding (string-append pad s)))))
 

Вы можете использовать эту функцию в time-stamp функции, которая возвращает строку в нужном формате:

 (define (time-stamp)
  (let* ((curr (time))
         (year (number->string (  1900 (list-ref curr 0))))
         (month (left-pad (number->string (  1 (list-ref curr 1))) 2 "0"))
         (day (left-pad (number->string (list-ref curr 2)) 2 "0"))
         (hour (left-pad (number->string (list-ref curr 3)) 2 "0"))
         (minute (left-pad (number->string (list-ref curr 4)) 2 "0"))
         (second (left-pad (number->string (list-ref curr 5)) 2 "0")))
    (string-append year month day hour minute second)))
 

Здесь list-ref вместо cadr , caddr , cadddr , и т.д. используется, это легче читать и менее подвержено ошибкам. Обратите внимание, что list-ref в списке используются индексы на основе нуля.

Затем просто вызовите time-stamp , чтобы получить строку, содержащую информацию о текущей временной метке. Вы можете использовать string->number , если вам действительно нужно число из этого, либо вызывая результат time-stamp , либо вызывая string->number определение time-stamp перед возвращением результата:

 > (time-stamp)
"20201229133118"
> (string->number (time-stamp))
20201229133150
 

Я выполнил вышеупомянутый тест в GIMP, так что в данный момент он показывает мое системное время. Вот пример использования вашего макетного теста:

 > (define (time) '(121 0 1 1 2 3))
> (time-stamp)
"20210101010203"
> (string->number (time-stamp))
20210101010203
 

В первой версии выше много дублирования кода time-stamp . Эта версия может показаться более очевидной для тех, кто не знаком с идиомами программирования Scheme, но вот версия в более функциональном стиле, которая устраняет большую часть дублирования кода:

 (define (time-stamp)
  (let* ((curr (time))
         (y (  1900 (car curr)))
         (m (  1 (cadr curr)))
         (tstamp-nums (apply list y m (cddr curr))))
    (apply string-append
           (map (lambda (x) (left-pad (number->string x) 2 "0"))
                tstamp-nums))))
 

Комментарии:

1. вау. Я полный новичок в TinyScheme, я просто попытался использовать какой-то сценарий для своих целей. И не знал список-ref и сделал это с помощью car(cdddr( и с помощью if. Но ваше решение абсолютно идеально… Отличная работа!

Ответ №2:

Наконец, я сделал это с этим:

   (define year (  1900 (car (time))))
  (define month (  1 (cadr (time))))
  (define day (caddr(time)))
  (define hour (cadddr(time)))
  (define minute (cadr(cdddr(time))))
  (define second (caddr(cdddr(time))))

  (set! newFileName (string-append inDir pathchar inFileName
        (number->string year)
        (if (< month 10) (string-append "0" (number->string month)) (number->string month))
        (if (< day 10) (string-append "0" (number->string day)) (number->string day))
        (if (< hour 10) (string-append "0" (number->string hour)) (number->string hour))
        (if (< minute 10) (string-append "0" (number->string minute)) (number->string minute))
        (if (< second 10) (string-append "0" (number->string second)) (number->string second))
             saveString))
 

Но я думаю, что ответ @ad absurdum намного лучше.