#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 намного лучше.