0

I have the following string:

// const asdf = 'asdf'
// // comment
// const asdf2 = asdf

And I want to run a regexp replace to make it look as follows:

const asdf = 'asdf'
// comment
const asdf2 = asdf

Basically, I'm trying to make a regexp that will comment out the first instance of // on every line. Here is my current implementation:

(setq comment "// const asdf = 'asdf'\n// // comment\n// const asdf2 = asdf")
(setq comment (replace-regexp-in-string "\\(//\\)" "" comment)))

But note that it is removing all matches to //, which gives the following output:

const asdf = 'asdf'
comment
const asdf2 = asdf

But I want to leave the second instance of // on the // // comment line. Any suggestions?

If your are curious, I am trying to solve this issue: https://github.com/fxbois/web-mode/issues/980 at this place in the code of web-mode: https://github.com/fxbois/web-mode/blob/master/web-mode.el#L9973

  • Wouldn't uncomment-region be better for this? – npostavs Mar 11 '18 at 22:35
  • @npostavs: Yeah, but it's not really clear what the real problem/question is, IMO. – Drew Mar 11 '18 at 22:41
1
  1. You are likely looking for this:

    (setq comment (replace-regexp-in-string "^// " "" comment))
    
  2. But are you sure you want to create a string and then act on it? A guess is that you really want to act on the text in a buffer directly, using re-search-forward followed by replace-match. Something like this:

    (defun foo ()
      (interactive)
      (save-excursion
        (goto-char (point-min))
        (while (re-search-forward "^// " nil t)
          (replace-match "")
          (forward-line 1))))
    
  • Ah, I didn't think the ^ operator would still work when comment has multiple lines. Thank you! I do agree that acting on the text directly in the buffer would be best, but that would require a large refactoring to web-mode, of which I am still getting familiar. – modulitos Mar 12 '18 at 1:57
  • 1
    This removes comments only when they occur at the very beginning of the line, in the first column. I didn't think that's what you wanted. – Omar Mar 12 '18 at 3:24
  • I ended up using a slightly updated regex, like so: (setq comment (replace-regexp-in-string "^ *// " "" comment)) which allows for spaces between the first column and the comment itself. – modulitos Mar 12 '18 at 16:02
3

C-hf replace-regexp-in-string actually covers this exact requirement (or it does in Emacs 25.3, at any rate).

To replace only the first match (if any), make REGEXP match up to \'
and replace a sub-expression, e.g.
 (replace-regexp-in-string "\\(foo\\).*\\'" "bar" " foo foo" nil nil 1)
   => " bar foo"

To replace the first match (if any) in each line of the string, you would use $ (which matches the end of a line) in place of \' (which matches the end of the text), like so:

(replace-regexp-in-string "\\(foo\\).*$" "bar"
                          " foo foo\nbaz\nbar foo foo"
                          nil nil 1)
 => " bar foo\nbaz\nbar bar foo"
  • Yes, I saw that, but it only replaces the first match in the provided string. Note that I am providing a string with multiple lines, so I either want to loop through each line individually and replace the first match, or use a regex replacer that remove the first match in each line. – modulitos Mar 12 '18 at 1:49
  • Ah, I see. In that case you would replace \\' (end-of-string) with $ (end-of-line). – phils Mar 12 '18 at 3:29
  • Ah, good to know! It seems like that solution would work as well - thank you. – modulitos Mar 12 '18 at 16:04
2

You could look for the pattern "beginning of line, spaces, //, spaces" and replace that with the empty string:

(replace-regexp-in-string "^\\s-*//\\s-*" "" comment)
  • This looks like a valid answer as well. Thank you! – modulitos Mar 12 '18 at 16:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.