How do i check if two regions have identical content? Is it possible to do so while ignoring language-specific whitespace?
Interactively, I do this one of a few ways, depending on the scenario.
First, if the regions are small -- e.g., lately I've been comparing some test output with the expected results, and both are just a single line -- I just edit so the lines are next to each other and compare visually.
Another "low tech" solution is to use isearch. If both regions are visible at the same time, I use
C-s at the start of one region, then repeatedly use
C-w to pick up characters from the region. Then I watch the highlighting of the other region -- when it stops I have found the difference.
For larger regions, I use
compare-windows. This has a way to ignore whitespace. If the regions are in the same buffer, just split windows and move point in each window to the start of one of the regions before beginning.
On the other hand if you wanted to do this programmatically, I think the basic idea is to use
buffer-substring and then
string=) to compare. I am not sure how you would ignore "language-specific whitespace", but I suppose one way would be to rewrite each string into a canonical form before comparing; for example by running a regular expression over them to strip such whitespace.
I'm glad you pointed those out. One man's "low tech" is another's "smart tech." Sep 24, 2015 at 16:59
I concur with the
compare-windowsapproaches :) I use both of those far more regularly than any more heavyweight approach.– philsSep 24, 2015 at 23:20
(As previous mentioned in the comments by glucas), a heavyweight approach to comparing regions is provided by the excellent
These commands "run Ediff on a pair of regions in specified buffers".
They prompt you first to specify which buffer(s) the regions come from, and then to mark and/or confirm the region to use in each of those buffers in turn, and then finally the ediff session is started to compare the two.
Obviously you'd only use this approach when the benefits of using ediff outweighed the more-cumbersome initialisation procedure.
Since this solution uses only CLI Diff, it also answers your "ignore whitespace" question, tweak diff's option to do whatever you want. Please
;; Diff two regions ;; Step 1: Select a region and `M-x diff-region-tag-selected-as-a' ;; Step 2: Select another region and `M-x diff-region-compare-with-b' (defun diff-region-format-region-boundary (b e) "Make sure lines are selected and B is less than E" (let (tmp rlt) ;; swap b e, make sure b < e (when (> b e) (setq tmp b) (setq b e) (set e tmp)) ;; select lines (save-excursion ;; Another workaround for evil-visual-line bug: ;; In evil-mode, if we use hotkey V or `M-x evil-visual-line` to select line, ;; the (line-beginning-position) of the line which is after the last selected ;; line is always (region-end)! Don't know why. (if (and (> e b) (save-excursion (goto-char e) (= e (line-beginning-position))) (boundp 'evil-state) (eq evil-state 'visual)) (setq e (1- e))) (goto-char b) (setq b (line-beginning-position)) (goto-char e) (setq e (line-end-position))) (setq rlt (list b e)) rlt)) (defun diff-region-tag-selected-as-a () "Select a region to compare" (interactive) (when (region-active-p) (let (tmp buf) ;; select lines (setq tmp (diff-region-format-region-boundary (region-beginning) (region-end))) (setq buf (get-buffer-create "*Diff-regionA*")) (save-current-buffer (set-buffer buf) (erase-buffer)) (append-to-buffer buf (car tmp) (cadr tmp)))) (message "Now select other region to compare and run `diff-region-compare-with-b`")) (defun diff-region-compare-with-b () "Compare current region with region selected by `diff-region-tag-selected-as-a' " (interactive) (if (region-active-p) (let (rlt-buf diff-output (fa (make-temp-file (expand-file-name "scor" (or small-temporary-file-directory temporary-file-directory)))) (fb (make-temp-file (expand-file-name "scor" (or small-temporary-file-directory temporary-file-directory))))) (when fb (setq tmp (diff-region-format-region-boundary (region-beginning) (region-end))) (write-region (car tmp) (cadr tmp) fb)) (setq rlt-buf (get-buffer-create "*Diff-region-output*")) (when (and fa (file-exists-p fa) fb (file-exists-p fb)) (save-current-buffer (set-buffer (get-buffer-create "*Diff-regionA*")) (write-region (point-min) (point-max) fa)) (setq diff-output (shell-command-to-string (format "diff -Nabur %s %s" fa fb))) ;; show the diff output (if (string= diff-output "") (message "Two regions are SAME!") (save-current-buffer (switch-to-buffer-other-window rlt-buf) (set-buffer rlt-buf) (erase-buffer) (insert diff-output) (diff-mode)))) (if (and fa (file-exists-p fa)) (delete-file fa)) (if (and fb (file-exists-p fb)) (delete-file fb))) (message "Please select region at first!")))
compare-windowsto compare different regions of the same buffer. Either way,
ediffis what you really need.