В elisp, как вычислить строку «var = value \ n ...» в переменные lisp с тем же именем? - PullRequest
3 голосов
/ 26 ноября 2011

Инструмент mplayer (midentify) выводит строки "готовые к обработке", предназначенные для оценки интерпретатором bash / sh / what.

Как я могу присвоить этим var-именам соответствующие значения как elisp var-names в emacs? Данные в виде строки (через shell-command-to-string)

Вот данные

ID_AUDIO_ID=0
ID_FILENAME=/home/axiom/abc.wav
ID_DEMUXER=audio
ID_AUDIO_FORMAT=1
ID_AUDIO_BITRATE=512000
ID_AUDIO_RATE=0
ID_AUDIO_NCH=1
ID_LENGTH=3207.00
ID_SEEKABLE=1
ID_CHAPTERS=0
ID_AUDIO_BITRATE=512000
ID_AUDIO_RATE=32000
ID_AUDIO_NCH=1
ID_AUDIO_CODEC=pcm
ID_EXIT=EOF

Ответы [ 4 ]

5 голосов
/ 27 ноября 2011

Вот процедура, которая принимает строку, содержащую вывод midentify, и возвращает список ассоциаций пар ключ-значение (что безопаснее, чем установка переменных Emacs в произвольном порядке). Он также имеет преимущество в том, что он разбирает числовые значения на фактические числа:

(require 'cl)  ; for "loop"
(defun midentify-output-to-alist (str)
  (setq str (replace-regexp-in-string "\n+" "\n" str))
  (setq str (replace-regexp-in-string "\n+\\'" "" str))
  (loop for index = 0 then (match-end 0)
        while (string-match "^\\(?:\\([A-Z_]+\\)=\\(?:\\([0-9]+\\(?:\\.[0-9]+\\)?\\)\\|\\(.*\\)\\)\\|\\(.*\\)\\)\n?" str index)
        if (match-string 4 str)
        do (error "Invalid line: %s" (match-string 4 str))
        collect (cons (match-string 1 str)
                      (if (match-string 2 str)
                          (string-to-number (match-string 2 str))
                        (match-string 3 str)))))

Вы бы использовали эту функцию так:

(setq alist (midentify-output-to-alist my-output))
(if (assoc "ID_LENGTH" alist)
    (setq id-length (cdr (assoc "ID_LENGTH" alist)))
  (error "Didn't find an ID_LENGTH!"))

РЕДАКТИРОВАТЬ: Модифицированная функция для правильной обработки пустых строк и завершающих строк.

Регулярное выражение действительно зверь; Регулярные выражения Emacs не известны своей легкостью на глазах. Чтобы разбить его немного:

  • Внешний шаблон ^(?:valid-line)|(.*). Он пытается сопоставить действительную строку или же сопоставляет всю строку (.*) в группе совпадений 4. Если (match-group 4 str) не равно nil, это указывает на то, что обнаружена неверная строка и возникла ошибка .
  • valid-line - это (word)=(?:(number)|(.*)). Если это соответствует, то часть имени пары имя-значение находится в строке соответствия 1, и если остальная часть строки соответствует номеру, то число находится в строке соответствия 2, в противном случае вся остальная часть строки в строке совпадений 3.
3 голосов
/ 26 ноября 2011

Возможно, есть лучший способ, но он должен это сделать:

(require 'cl)

(let ((s "ID_AUDIO_ID=0
ID_FILENAME=/home/axiom/abc.wav
ID_DEMUXER=audio
ID_AUDIO_FORMAT=1
ID_AUDIO_BITRATE=512000
ID_AUDIO_RATE=0
ID_AUDIO_NCH=1
ID_LENGTH=3207.00
ID_SEEKABLE=1
ID_CHAPTERS=0
ID_AUDIO_BITRATE=512000
ID_AUDIO_RATE=32000
ID_AUDIO_NCH=1
ID_AUDIO_CODEC=pcm
ID_EXIT=EOF"))
  (loop for p in (split-string s "\n")
    do
    (let* ((elements (split-string p "="))
          (key (elt elements 0))
          (value (elt elements 1)))
      (set (intern key) value))))
2 голосов
/ 26 ноября 2011

Вот функция, которую вы можете запустить в буфере вывода:

(defun set-variables-from-shell-assignments ()
  (goto-char (point-min))
  (while (< (point) (point-max))
    (and (looking-at "\\([A-Z_]+\\)=\\(.*\\)$")
       (set (intern (match-string 1)) (match-string 2)))
    (forward-line 1)))
1 голос
/ 28 ноября 2011

Я не думаю, что регулярное выражение действительно то, что нужно.Вам нужно разделить вашу строку на \n и =, так что вы просто говорите то же самое для интерпретатора.

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

(defun set=(str)
  (mapcar (lambda(arg)
            (set
              (intern (car arg))
              (cadr arg)))
    (mapcar (lambda(arg)
              (split-string arg "=" t))
      (split-string
        str
        "\n" t))))

(set=
"ID_AUDIO_ID=0
ID_FILENAME=/home/axiom/abc.wav
ID_DEMUXER=audio
ID_AUDIO_FORMAT=1
ID_AUDIO_BITRATE=512000
ID_AUDIO_RATE=0
ID_AUDIO_NCH=1
ID_LENGTH=3207.00
ID_SEEKABLE=1
ID_CHAPTERS=0
ID_AUDIO_BITRATE=512000
ID_AUDIO_RATE=32000
ID_AUDIO_NCH=1
ID_AUDIO_CODEC=pcm
ID_EXIT=EOF")
...