2012-11-18 39 views
2

我想在Emacs中建立一个正则表达式来清理我的R代码。Regexp Emacs的R评论

一个我遇到的问题是,有不同类型的注释: 你有那些有一定量的空白(1),例如:

 # This is a comment: 
# This is also a comment 

,或者你有这样的情况下( 2):

require(lattice) # executable while the comment is informative 

的想法是,我要对齐的意见时,他们是第二类(的东西是可执行文件后),同时排除那些第一类。

理想情况下,它将对齐第一类的所有评论,但不包括第一类评论。

例子:

funfun <- function(a, b) { 
# This is a function 
    if (a == b) { # if a equals b 
     c <- 1 # c is 1 
    } 
    } 
# 

要:

funfun <- function(a, b) { 
# This is a function 
    if (a == b) { # if a equals b 
     c <- 1  # c is 1 
    } 
    } 
# 

我发现了一个正则表达式做那些第一类的替代品,所以后来我能够将它们对齐每个段落(mark-段)。这种工作很好。

问题是,则回代:

(replace-regexp "^\\s-+#+" "bla" nil (point-min) (point-max)) 

这代替从行的开头,有空白的任何量和类似的注释字符的任何量:

 ######### 

 bla 

问题是我想将它们重新放回原来的位置最后,所以“bla”必须回到相同数量的空白和相同数量的#中。

希望有人能够理解我正在尝试做什么,并有一个更好的方法或知道如何解决这个正则表达式部分。

​​

+0

我很难理解你问,究竟是什么。你想用一些文本替换最初的空格和注释标记,然后对该行执行转换,然后恢复空白和注释标记? – user4815162342

+0

@wvxvw我得到你wvxcw。只是我意识到只有两种评论。所以这是阻止制作脚本来清除任何用户需求的唯一问题! – PascalVKooten

+0

@ user4815162342我实际上只是想暂时改变这些类型(1)的注释,以排除它们对齐每个段落的第二种类型。 – PascalVKooten

回答

1

嗯,这里是在做一些我以为你是经过一番疯狂的尝试。它似乎工作,但它需要大量的测试和抛光:

(defun has-face-at-point (face &optional position) 
    (unless position (setq position (point))) 
    (unless (consp face) (setq face (list face))) 
    (let ((props (text-properties-at position))) 
    (loop for (key value) on props by #'cddr 
      do (when (and (eql key 'face) (member value face)) 
       (return t))))) 

(defun face-start (face) 
    (save-excursion 
    (while (and (has-face-at-point face) (not (bolp))) 
     (backward-char)) 
    (- (point) (save-excursion (move-beginning-of-line 1)) (if (bolp) 0 -1)))) 

(defun beautify-side-comments() 
    (interactive) 
    ;; Because this function does a lot of insertion, it would 
    ;; be better to execute it in the temporary buffer, while 
    ;; copying the original text of the file into it, such as 
    ;; to prevent junk in the formatted buffer's history 
    (let ((pos (cons (save-excursion 
        (beginning-of-line) 
        (count-lines (point-min) (point))) 
        (- (save-excursion (end-of-line) (point)) (point)))) 
     (content (buffer-string)) 
     (comments '(font-lock-comment-face font-lock-comment-delimiter-face))) 
    (with-temp-buffer 
     (insert content) 
     (goto-char (point-min)) 
     ;; thingatpt breaks if there are overlays with their own faces 
     (let* ((commentp (has-face-at-point comments)) 
      (margin 
       (if commentp (face-start comments) 0)) 
      assumed-margin pre-comment commented-lines) 
     (while (not (eobp)) 
      (move-end-of-line 1) 
      (cond 
      ((and (has-face-at-point comments) 
       commentp)   ; this is a comment continued from 
             ; the previous line 
      (setq assumed-margin (face-start comments) 
        pre-comment 
        (buffer-substring-no-properties 
        (save-excursion (move-beginning-of-line 1)) 
        (save-excursion (beginning-of-line) 
            (forward-char assumed-margin) (point)))) 
      (if (every 
       (lambda (c) (or (char-equal c ?\) (char-equal c ?\t))) 
       pre-comment) 
       ;; This is the comment preceded by whitespace 
       (setq commentp nil margin 0 commented-lines 0) 
       (if (<= assumed-margin margin) 
        ;; The comment found starts on the left of 
        ;; the margin of the comments found so far 
        (save-excursion 
        (beginning-of-line) 
        (forward-char assumed-margin) 
        (insert (make-string (- margin assumed-margin) ?\)) 
        (incf commented-lines)) 
       ;; This could be optimized by going forward and 
       ;; collecting as many comments there are, but 
       ;; it is simpler to return and re-indent comments 
       ;; (assuming there won't be many such cases anyway. 
       (setq margin assumed-margin) 
       (move-end-of-line (1- (- commented-lines)))))) 
      ((has-face-at-point comments) 
      ;; This is the fresh comment 
      ;; This entire block needs refactoring, it is 
      ;; a repetition of the half the previous blockp 
      (setq assumed-margin (face-start comments) 
        pre-comment 
        (buffer-substring-no-properties 
        (save-excursion (move-beginning-of-line 1)) 
        (save-excursion (beginning-of-line) 
            (forward-char assumed-margin) (point)))) 
      (unless (every 
        (lambda (c) 
         (or (char-equal c ?\) (char-equal c ?\t))) 
        pre-comment) 
       (setq commentp t margin assumed-margin commented-lines 0))) 
      (commentp 
      ;; This is the line directly after a block of comments 
      (setq commentp nil margin assumed-margin commented-lines 0))) 
      (unless (eobp) (forward-char))) 
     ;; Retrieve back the formatted contnent 
     (setq content (buffer-string)))) 
    (erase-buffer) 
    (insert content) 
    (beginning-of-buffer) 
    (forward-line (car pos)) 
    (end-of-line) 
    (backward-char (cdr pos)))) 

我也复制了上引擎收录了更好的可读性:http://pastebin.com/C2L9PRDM

编辑:这应该恢复鼠标位置,但不会恢复滚动位置(可以工作,也许,我只需要寻找如何滚动存储)。

+0

大量的代码。 :)你真的需要通过他们的字体锁面找​​到评论吗? 'forward-comment'使用内置的语法扫描器。 – user4815162342

+0

'前向评论'可以采取负数,但我没有用R进行测试,所以我不知道它在实践中效果如何。 – user4815162342

+0

最初我有一个解决方案,我只用了一个while循环。问题是,即使是少量代码,也需要大约2秒钟的时间。我假设一个很长的缓冲区需要很长时间。至少,效率不高。有了这么多的代码,我很难相信它很快?是吗? – PascalVKooten

0

尝试

(replace-regexp "^\\(\\s-+\\)#" "\\1bla" nil (point-min) (point-max)) 

然后

(replace-regexp "^\\(\\s-+\\)bla+" "\\1#" nil (point-min) (point-max)) 

,但如果我理解你很好,我可能会做这样的事情:

(align-string "\b\s-#" begin end) 
+0

align-strings不是函数吗? – PascalVKooten

+0

问题是,当你有一个代码块#时,它不会计算###所需的数量(然后你必须替换多个#,但更重要的是,你会如何返回它们? – PascalVKooten

+0

正确的函数名是align-string(没有s,我已经编辑了我的答案) –

1

align-regexp是Emacs的魔法真棒位你需要:

(defun align-comments() 
    "align R comments depending on whether at start or in the middle." 
    (interactive) 
    (align-regexp (point-min) (point-max) 
    "^\\(\\s-*?\\)\\([^[:space:]]+\\)\\(\\s-+\\)#" 3 1 nil) ;type 2 regex 
    (align-regexp (point-min) (point-max) 
    "^\\(\\s-*\\)\\(\\s-*\\)#" 2 0 nil))     ;type 1 regex 

前:

# a comment type 1 
     ## another comment type 1 
a=1 ###### and a comment type 2 with lots of #####'s 
a.much.longer.variable.name=2   # and another, slightly longer type 2 comment  
     ## and a final type 1 

后:

 # a comment type 1 
     ## another comment type 1 
a=1       ###### and a comment type 2 with lots of #####'s 
a.much.longer.variable.name=2 # and another, slightly longer type 2 comment  
     ## and a final type 1 
+0

它很接近!如果可以的话扩展这个以便类型1注释仍然可以有空白之前,它已经被解决了(但我认为这就是问题所在) – PascalVKooten

+0

实际上,它可以在暂存缓冲区中完美工作,但在示例图片中,它还包括类型1评论和将所有类型的东西都对齐。 – PascalVKooten

+0

几乎在那里。我们只需要类型2的正则表达式,表示匹配任何内容,但不包括全部空白。像(。+?)|〜(\ s- +)。 –