3

Is there an existing package that targets subexps for replacement during query-replace-regexp?

For example given the following

var foo1 = blah( properties, property_id);

var foo2 = blah(properties, property_id );

var foo3 = blah(  properties, property_id      );

I want to remove the padding around braces.

Normally, the way is to subgroup the bits you want to keep and assemble a replacement.

search:

\(var .* = blah\s-*(\)\s-*\(.*?\)\s-*\()\)

replace:

\1\2\3

However, it seems much easier to some up with a regexp that groups the bits I want to delete than the otherway around. Like this one:

var .* = blah\s-*(\(\s-*\).*?\(\s-*\))

I'll get two subgroups out of this. How can I target them for replacement?

EDIT: I'm asking for an interactive way to "invert" the given regexp. So the interface would be similar to query-replace-regexp

  1. enter regexp
  2. enter replacement for group 1
  3. enter replacement for group 2

2 Answers 2

1

I think some variation of this should work:

(defun remove-padding ()
  (interactive)
  (while (search-forward-regexp
          "var .* = [a-zA-Z_]+\\s-*(\\(\\s-*\\).*?\\(\\s-*\\))"
          nil t)
    ;; Replace the 2 subexpressions with nothing
    (replace-match "" nil t nil 2)
    (replace-match "" nil t nil 1)))

However, you might also consider using a tool like indent depending on what your use cases are.

EDIT: Below is a very minimal interactive version. The function query-replace-regexp is very complex and I have made no attempt to reproduce all of it's functionality.

(require 're-builder)
(defun query-replace-subexpressions (regexp replacements)
  "REPLACEMENTS need to be in reverse order if passed from lisp!"
  ;; Read the correct number of subexpressions
  (interactive
   (let* ((re (read-from-minibuffer "Query replace subexps: "))
          (num-subexps (reb-count-subexps re))
          (replacement-list nil)
          (replacements (dotimes (rep num-subexps)
                          (setq replacement-list
                                (cons
                                 (read-from-minibuffer
                                  (format "Replace subexpression %s with: " rep))
                                 replacement-list)))))
     (list re replacement-list)))
  ;; Search
  (let ((len (length replacements)))
    (while (search-forward-regexp regexp nil t)
      (replace-highlight (match-beginning 0) (match-end 0)
                         (point-min) (point-max) regexp
                         t case-fold-search)
      ;; Query
      (when (save-match-data (y-or-n-p "Replace this occurrence? "))
        ;; Make all the replacements
        (dotimes (i len)
          (replace-match (nth i replacements) nil nil nil (- len i)))))
    (replace-dehighlight)))


;; Test it out below
(query-replace-subexpressions
 "var .* = [a-zA-Z_]+\\s-*(\\(\\s-*\\).*?\\(\\s-*\\))"
 '("" ""))

var foo1 = blah(properties, property_id    );

var foo2 = blah (properties, property_id );

var foo3 = blah( properties, property_id      );
Sign up to request clarification or add additional context in comments.

2 Comments

I clarified the question. "Interactive" is the key here.
This answers my question. I also made a version hooking into query-replace-regexp below.
1

I've made it hooking into query-replace-regexp on github

Here is a paste in case of link rot:

;; -*- lexical-binding: t -*-

(provide inverted-replace)

(require 're-builder)
(require 'parallel-replace)

(defun inverted-replace-generate-replacement (from to)
  "invert result of current match (match-string 0)"
  (let ((string (match-string 0))
        (count (reb-count-subexps from))
        (replacements (parallel-replace-read-list to)))
    (save-match-data
      (string-match from string)
      (dotimes (i count)
        (setq string (replace-match (nth i replacements) nil nil string (- count i)))))
    string))

(defun inverted-replace-regexp (from to)
  (interactive (destructuring-bind (from to _)
                   (query-replace-read-args "inverted-replace-regexp: " t)
                 (list from to)))
  (query-replace-regexp from
                        (quote (replace-eval-replacement
                                replace-quote
                                (inverted-replace-generate-replacement from to)))
                        nil (and (and transient-mark-mode mark-active)
                               (region-beginning))
                        (and (and transient-mark-mode mark-active) (region-end))))

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.