2

RコードをクリーンアップするためにEmacsで正規表現を作成したいと思います。

私が遭遇した問題の1つは、さまざまな種類のコメントがあることでした。一定量の空白(1)を持つコメントがあります。例:

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

または、次のような状況があります(2):

require(lattice) # executable while the comment is informative

アイデアは、コメントが第2の種類の場合(実行可能なものの後)に、第1の種類のコメントを除外して、コメントを揃えたいというものです。

理想的には、すべてのコメントを第1種のコメント間で整列させますが、第1種のコメント間では整列させません。

例:

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 
    }
  }  
# 

最初の種類のものを置き換える正規表現を見つけたので、段落ごとにそれらを整列させることができました(マーク-段落)。それはちょっとうまくいきました。

問題は逆置換です:

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

これは、行の先頭から、次のような任意の量の空白と任意の量のコメント文字に置き換えられます。

     #########   

の中へ

     bla

問題は、それらを元の状態に戻したいので、「bla」は同じ量の空白と同じ量の#に戻らなければならないということです。

うまくいけば、誰かが私がやろうとしていることを理解し、アプローチのより良いアイデアを持っているか、この正規表現の部分を解決する方法を知っています。

ここに画像の説明を入力してください

4

3 に答える 3

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

編集:これはマウスの位置を復元するはずですが、スクロールの位置は復元しません(おそらく、スクロールがどのように保存されているかを探す必要があります)。

于 2012-11-18T12:58:06.707 に答える
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
于 2012-11-19T00:41:23.313 に答える
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)
于 2012-11-18T14:10:12.563 に答える