2012-11-18 40 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- +)。 –