Cách dễ nhất để thực hiện một chức năng như định dạng chuỗi thời gian


12

Các format-time-string chức năng phải mất một chuỗi và thay thế một tập hợp các cấu trúc đặc biệt trong chuỗi (ký tự preceeded bằng %) với một số văn bản cụ thể.

Tôi muốn thực hiện một chức năng như thế trong một chức năng của riêng tôi:

  • Tôi có một khoảng cách giữa ký tự và ký hiệu như : '((?n . name) (?r . reputation)).
  • Các chức năng nên có một chuỗi như "My name is %n, and my rep is %r".
  • Nó nên thay thế %n%rvới giá trị của các biến namereputation, và trả về kết quả.
  • Nó sẽ xử lý %%giống như format-time-string(thay thế nó %).

Cách dễ nhất để thực hiện chức năng này là gì?
Có một thư viện hoặc chức năng sẽ tạo điều kiện này? Xử lý %%chính xác là rất quan trọng.

Câu trả lời:


19

Các chức năng mặc định được sử dụng là format-specformat-spec-make:

(let* ((name "Malabarba")
       (reputation "good")
       (fs (format-spec-make ?n name ?r reputation)))
  (format-spec "My name is %n, with a %r reputation.  %% is kept." fs))

1
Thật tuyệt, không ngờ điều đó lại tồn tại ở Emacs. Điều đặc biệt tốt là có xử lý lỗi thô sơ cho các mã định dạng không hợp lệ được bao gồm.
wasamasa

7

Vì elisp có các phương tiện khá thô sơ để xử lý các chuỗi, tốt hơn là đặt chuỗi định dạng của bạn vào một bộ đệm và lặp lại qua đó:

(defvar malabarba-alist '((?n . "Malabarba") (?r . 7488) (?% . "%")))

(defun malabarba-format (string)
  (with-temp-buffer
    (insert string)
    (goto-char 1)
    (while (search-forward "%" nil t)
      (let ((s (cdr (assoc (char-after) malabarba-alist))))
        (cond
          (s (delete-char -1) (delete-char 1) (insert (format "%s" (eval s))))
          (t (unless (eobp) (forward-char))))))
    (buffer-string)))

Một sự tinh tế nhỏ - điều này không bị phá vỡ khi có một chuỗi %ở cuối chuỗi vì char-aftertrả về nilở cuối bộ đệm.


Vâng, cách tiếp cận này, về tiến trình thông qua chuỗi một lần, cũng được sử dụng bởi @AlanShutko, có ý nghĩa hơn. Tôi đã xóa câu trả lời của mình.
vẽ

3

Đây là mã mà tôi sử dụng cho chuỗi thời gian định dạng cho lịch giả:

(defun mystcal-format-time (format-string time)
  "Format time
%Y is the year.
%m is the numeric month.
%B is the full name of the month.
%d is the day of the month, zero-padded, %e is blank-padded.
%u is the numeric day of week from 1 (Monday) to 7, %w from 0 (Sunday) to 6.
%A is the locale's full name of the day of week.
%H is the hour on a 24-hour clock, %I is on a 12-hour clock, %k is like %H
 only blank-padded, %l is like %I blank-padded.
%p is the locale's equivalent of either AM or PM.
%M is the minute.
%S is the second."
  (let* (output
         (start 0)
         (decoded-time (if (listp time)
                           time
                         (mystcal-decode-time time)))
         (turn (nth 0 decoded-time))
         (minute (nth 1 decoded-time))
         (hour (nth 2 decoded-time))
         (day (nth 3 decoded-time))
         (month (mystcal-month decoded-time))
         (year (nth 5 decoded-time))
         (weekday (mystcal-weekday-of-day day))
         (hour12 (mod hour 12)))
    (save-match-data
      (while (string-match "%" format-string start)
        (let ((index (match-beginning 0)))
          ;; First copy non-format text
          (setq output (concat output (substring format-string start 
                                                 index)))
          ;; Process format codes here
          (let (fmted)
            (setq output (concat output 
                                 (case (aref format-string (1+ index))
                                   (?Y (number-to-string year))
                                   (?m (number-to-string month))
                                   (?B (mystcal-month-name month))
                                   (?d (format "%02d" day))
                                   (?e (format "%2d" day))
                                   (?u (number-to-string (if (zerop weekday)
                                                             7
                                                           weekday)))
                                   (?w (number-to-string weekday))
                                   (?A (mystcal-weekday-name 
                                        (mystcal-weekday-of-day day)))
                                   (?H (format "%02d" hour))
                                   (?k (format "%2d" hour))
                                   (?I (format "%02d" (if (zerop hour12) 12 hour12)))
                                   (?l (format "%2d" (if (zerop hour12) 12 hour12)))
                                   (?p (if (< hour 12)
                                           "AM" "PM"))
                                   (?M (format "%02d" minute))
                                   (?S "00")))))
          (setq start (+ 2 index)))))
    (setq output (concat output (substring format-string start)))
    output))
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.