2011-11-26 58 views
3

一个mplayer工具(midentify)输出准备由bash/sh /任何解释器评估的“shell-ready”行。在elisp中,如何评估一个字符串“var = value n ...”为相同名称的lisp变量?

如何将这些var-name作为emacs中的elisp var-names分配给它们的对应值? 的数据是在一个字符串(通过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 

回答

5

下面是一个例程,需要st环包含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 regexps并不以其在眼睛上的易用性而闻名。把它分解一下:

  • 最外层的模式是^(?:valid-line)|(.*)。它会尝试匹配有效行,或者匹配匹配组4中的整行(.*)。如果(match-group 4 str)不是nil,则表示遇到无效行,并且会引发错误。
  • valid-line(word)=(?:(number)|(.*))。如果匹配,则名称 - 值对的名称部分位于匹配字符串1中,如果该行的其余部分匹配一个数字,则该数字位于匹配字符串2中,否则该行的整个剩余部分是在匹配字符串3.
+0

我喜欢你的* willy-nilly *评论,因为我只是喜欢这句话,而且它很有道理。我一直想知道这个数字问题(我想我可以只使用*数字到字符串*),所以你做的很好......但是*圣·摩尔*!它需要我花一个星期的时间才能找出正则表达式(我已经习惯了扩展正则表达式,并减少了反斜杠:) ......我会习惯它,我确信.... *但是:(我得到一个错误:*(错误“无效的行:”) 信号(错误(“无效的行:”)) 错误(“无效的行:%s”“”) (if(match-string 4 str)(错误“Invalid line:%s”(match-string 4 str))(cons(ma * –

+0

PS。*错误*似乎是由尾随的换行引起的。 –

+0

* @ Sean:*感谢您添加换行符......在附注中:我围绕正则表达式问题(至少现在是这样,直到我更习惯于elisp),我做了一个包装,希望没有一些可怕的副作用这我还没有意识到..我已经把它叫做[Ree:Regex; Easy on the Eyes](http://paste.ubuntu.com/751190/):)它使用C-),C- ),C- |插入Unicode的外观,反之亦然根据3个Unicode字符中任何一个字符的存在情况切换值...例如:'(ree“^❨:❨[A-Z _] +❩=❨❨:[0-9] +❨: \。[0-9] +❩❩❙❨。*❩❩❙❨。*❩❩\ n?“)' –

3

有可能是一个更好的办法,但这应该这样做:

 
(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)))) 
+0

看起来不错。它根据样本数据做了一些技巧,但是它会产生包含空格的文件名的问题,例如''ID_FILENAME =/home/axiom/a \\ b \\ \\ c.wav'(这是什么midentify输出)..或其他一些使用引号字符串(带空格)的情况......有什么方法可以调整'split-string'来迎合这个吗? –

+0

我刚刚更改了第一次调用split string以仅在换行符上进行拆分。 –

+0

谢谢*卢克*。它工作正常,现在... –

2

这里是你可以运行功能在输出缓冲区上:

(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

这应该是[A-Z _] +在这种情况下。 – nschum

+0

谢谢*凯文*。这个缓冲区(VS字符串)的方法肯定会派上用场(很快)... –

+0

谢谢你的'''loking-at''的东西。我真的缺乏这个。 – desudesudesu

1

我不认为regexp是真正需要的。你需要将你的字符串拆分为\n=,所以你只是对口译员说完全一样。

我想你也可以用intern从字符串(和设置变量)中获取符号。我第一次使用它,所以如果我错了,请在这里留言。无论如何,如果列表是你想要的,只需删除顶层mapcar。

(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") 
+0

谢谢..这不是我以前的样子(但是它在那里),但是,对我来说,看到这个如何分解输入的例子是非常好的。我是一个初学者, elisp,像这样的东西很好指代。 –