Peter Siebel - Practical Common Lisp
Здесь есть возможность читать онлайн «Peter Siebel - Practical Common Lisp» весь текст электронной книги совершенно бесплатно (целиком полную версию без сокращений). В некоторых случаях можно слушать аудио, скачать через торрент в формате fb2 и присутствует краткое содержание. Год выпуска: 2005, ISBN: 2005, Издательство: Apress, Жанр: Программирование, на английском языке. Описание произведения, (предисловие) а так же отзывы посетителей доступны на портале библиотеки ЛибКат.
- Название:Practical Common Lisp
- Автор:
- Издательство:Apress
- Жанр:
- Год:2005
- ISBN:1-59059-239-5
- Рейтинг книги:4 / 5. Голосов: 1
-
Избранное:Добавить в избранное
- Отзывы:
-
Ваша оценка:
- 80
- 1
- 2
- 3
- 4
- 5
Practical Common Lisp: краткое содержание, описание и аннотация
Предлагаем к чтению аннотацию, описание, краткое содержание или предисловие (зависит от того, что написал сам автор книги «Practical Common Lisp»). Если вы не нашли необходимую информацию о книге — напишите в комментариях, мы постараемся отыскать её.
Practical Common Lisp — читать онлайн бесплатно полную книгу (весь текст) целиком
Ниже представлен текст книги, разбитый по страницам. Система сохранения места последней прочитанной страницы, позволяет с удобством читать онлайн бесплатно книгу «Practical Common Lisp», без необходимости каждый раз заново искать на чём Вы остановились. Поставьте закладку, и сможете в любой момент перейти на страницу, на которой закончили чтение.
Интервал:
Закладка:
(defun non-terminated-type (encoding)
(ecase encoding
(0 'iso-8859-1-string)
(1 'ucs-2-string)))
(defun terminated-type (encoding)
(ecase encoding
(0 'iso-8859-1-terminated-string)
(1 'ucs-2-terminated-string)))
Then string-args
uses the encoding byte, the length, and the terminator to determine several of the arguments to be passed to read-value
and write-value
by the :reader
and :writer
of id3-encoded-string
. One of the length and terminator arguments to string-args
should always be NIL
.
(defun string-args (encoding length terminator)
(cond
(length
(values (non-terminated-type encoding) :length length))
(terminator
(values (terminated-type encoding) :terminator terminator))))
With those helpers, the definition of id3-encoded-string
is simple. One detail to note is that the keyword—either :length
or :terminator
—used in the call to read-value
and write-value
is just another piece of data returned by string-args
. Although keywords in arguments lists are almost always literal keywords, they don't have to be.
(define-binary-type id3-encoded-string (encoding length terminator)
(:reader (in)
(multiple-value-bind (type keyword arg)
(string-args encoding length terminator)
(read-value type in keyword arg)))
(:writer (out string)
(multiple-value-bind (type keyword arg)
(string-args encoding length terminator)
(write-value type out string keyword arg))))
Now you can define a text-info
mixin class, much the way you defined generic-frame
earlier.
(define-binary-class text-info-frame ()
((encoding u1)
(information (id3-encoded-string :encoding encoding :length (bytes-left 1)))))
As when you defined generic-frame
, you need access to the size of the frame, in this case to compute the :length
argument to pass to id3-encoded-string
. Because you'll need to do a similar computation in the next class you define, you can go ahead and define a helper function, bytes-left
, that uses current-binary-object
to get at the size of the frame.
(defun bytes-left (bytes-read)
(- (size (current-binary-object)) bytes-read))
Now, as you did with the generic-frame
mixin, you can define two version-specific concrete classes with a minimum of duplicated code.
(define-binary-class text-info-frame-v2.2 (id3v2.2-frame text-info-frame) ())
(define-binary-class text-info-frame-v2.3 (id3v2.3-frame text-info-frame) ())
To wire these classes in, you need to modify find-frame-class
to return the appropriate class name when the ID indicates the frame is a text information frame, namely, whenever the ID starts with T and isn't TXX or TXXX .
(defun find-frame-class (name)
(cond
((and (char= (char name 0) #\T)
(not (member name '("TXX" "TXXX") :test #'string=)))
(ecase (length name)
(3 'text-info-frame-v2.2)
(4 'text-info-frame-v2.3)))
(t
(ecase (length name)
(3 'generic-frame-v2.2)
(4 'generic-frame-v2.3)))))
Comment Frames
Another commonly used frame type is the comment frame, which is like a text information frame with a few extra fields. Like a text information frame, it starts with a single byte indicating the string encoding used in the frame. That byte is followed by a three-character ISO 8859-1 string (regardless of the value of the string encoding byte), which indicates what language the comment is in using an ISO-639-2 code, for example, "eng" for English or "jpn" for Japanese. That field is followed by two strings encoded as indicated by the first byte. The first is a null-terminated string containing a description of the comment. The second, which takes up the remainder of the frame, is the comment text itself.
(define-binary-class comment-frame ()
((encoding u1)
(language (iso-8859-1-string :length 3))
(description (id3-encoded-string :encoding encoding :terminator +null+))
(text (id3-encoded-string
:encoding encoding
:length (bytes-left
(+ 1 ; encoding
3 ; language
(encoded-string-length description encoding t)))))))
As in the definition of the text-info
mixin, you can use bytes-left
to compute the size of the final string. However, since the description
field is a variable-length string, the number of bytes read prior to the start of text
isn't a constant. To make matters worse, the number of bytes used to encode description
is dependent on the encoding. So, you should define a helper function that returns the number of bytes used to encode a string given the string, the encoding code, and a boolean indicating whether the string is terminated with an extra character.
(defun encoded-string-length (string encoding terminated)
(let ((characters (+ (length string) (if terminated 1 0))))
(* characters (ecase encoding (0 1) (1 2)))))
And, as before, you can define the concrete version-specific comment frame classes and wire them into find-frame-class
.
(define-binary-class comment-frame-v2.2 (id3v2.2-frame comment-frame) ())
(define-binary-class comment-frame-v2.3 (id3v2.3-frame comment-frame) ())
(defun find-frame-class (name)
(cond
((and (char= (char name 0) #\T)
(not (member name '("TXX" "TXXX") :test #'string=)))
(ecase (length name)
(3 'text-info-frame-v2.2)
(4 'text-info-frame-v2.3)))
((string= name "COM") 'comment-frame-v2.2)
((string= name "COMM") 'comment-frame-v2.3)
(t
(ecase (length name)
(3 'generic-frame-v2.2)
(4 'generic-frame-v2.3)))))
Extracting Information from an ID3 Tag
Now that you have the basic ability to read and write ID3 tags, you have a lot of directions you could take this code. If you want to develop a complete ID3 tag editor, you'll need to implement specific classes for all the frame types. You'd also need to define methods for manipulating the tag and frame objects in a consistent way (for instance, if you change the value of a string in a text-info-frame
, you'll likely need to adjust the size); as the code stands, there's nothing to make sure that happens. [279] Ensuring that kind of interfield consistency would be a fine application for :after methods on the accessor generic functions. For instance, you could define this :after method to keep size in sync with the information string: (defmethod (setf information) :after (value (frame text-info-frame)) (declare (ignore value)) (with-slots (encoding size information) frame (setf size (encoded-string-length information encoding nil))))
Интервал:
Закладка:
Похожие книги на «Practical Common Lisp»
Представляем Вашему вниманию похожие книги на «Practical Common Lisp» списком для выбора. Мы отобрали схожую по названию и смыслу литературу в надежде предоставить читателям больше вариантов отыскать новые, интересные, ещё непрочитанные произведения.
Обсуждение, отзывы о книге «Practical Common Lisp» и просто собственные мнения читателей. Оставьте ваши комментарии, напишите, что Вы думаете о произведении, его смысле или главных героях. Укажите что конкретно понравилось, а что нет, и почему Вы так считаете.